4 * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
7 * KiTae Kim <kt920.kim@samsung.com>
8 * SeokYeon Hwang <syeon.hwang@samsung.com>
9 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
27 /* First, include the header file for the plugin, to bring in the
28 * object definition and other useful things.
46 #include "gstemulcommon.h"
48 typedef struct _GstEmulEnc
76 typedef struct _GstEmulEncClass
78 GstElementClass parent_class;
80 GstPadTemplate *sinktempl;
81 GstPadTemplate *srctempl;
84 static GstElementClass *parent_class = NULL;
86 static void gst_emulenc_base_init (GstEmulEncClass *klass);
87 static void gst_emulenc_class_init (GstEmulEncClass *klass);
88 static void gst_emulenc_init (GstEmulEnc *emulenc);
89 static void gst_emulenc_finalize (GObject *object);
91 static gboolean gst_emulenc_setcaps (GstPad *pad, GstCaps *caps);
92 static gboolean gst_emulenc_sink_event (GstPad *pad, GstEvent *event);
93 static GstFlowReturn gst_emulenc_chain (GstPad *pad, GstBuffer *buffer);
95 static gboolean gst_emulenc_src_event (GstPad *pad, GstEvent *event);
96 static GstStateChangeReturn gst_emulenc_change_state (GstElement *element, GstStateChange transition);
98 int gst_emul_codec_init (GstEmulEnc *emulenc);
99 void gst_emul_codec_deinit (GstEmulEnc *emulenc);
100 int gst_emul_codec_encode_video (GstEmulEnc *emulenc, guint8 *in_buf, guint in_size,
101 GstBuffer **out_buf, GstClockTime in_timestamp);
103 int gst_emul_codec_dev_open (GstEmulEnc *emulenc);
106 #define GST_EMULENC_PARAMS_QDATA g_quark_from_static_string("emulenc-params");
112 gst_emulenc_base_init (GstEmulEncClass *klass)
114 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
115 GstCaps *sinkcaps, *srccaps;
116 GstPadTemplate *sinktempl, *srctempl;
117 const char *mimetype = "video/x-h264";
119 gchar *longname, *classification;
122 (CodecInfo *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
123 GST_EMULENC_PARAMS_QDATA);
125 longname = g_strdup_printf ("%s Encoder", info->codec_longname);
127 classification = g_strdup_printf ("Codec/Encoder/%s",
128 (info->media_type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio");
130 gst_element_class_set_details_simple (element_class,
133 "accelerated codec for Tizen Emulator",
134 "Kitae Kim <kt920.kim@samsung.com>");
137 g_free (classification);
139 sinkcaps = gst_caps_new_simple (mimetype,
140 "width", GST_TYPE_INT_RANGE, 16, 4096,
141 "height", GST_TYPE_INT_RANGE, 16, 4096,
142 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
144 sinkcaps = gst_caps_from_string ("unknown/unknown");
148 srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
150 // srcaps = gst_emul_codectype_to_audio_caps ();
153 srccaps = gst_caps_from_string ("unknown/unknown");
156 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
157 GST_PAD_ALWAYS, sinkcaps);
158 srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
159 GST_PAD_ALWAYS, srccaps);
161 gst_element_class_add_pad_template (element_class, srctempl);
162 gst_element_class_add_pad_template (element_class, sinktempl);
164 klass->sinktempl = sinktempl;
165 klass->srctempl = srctempl;
169 gst_emulenc_class_init (GstEmulEncClass *klass)
171 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
172 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
174 parent_class = g_type_class_peek_parent (klass);
177 gobject_class->set_property = gst_emulenc_set_property
178 gobject_class->get_property = gst_emulenc_get_property
181 gobject_class->finalize = gst_emulenc_finalize;
183 gstelement_class->change_state = gst_emulenc_change_state;
187 gst_emulenc_init (GstEmulEnc *emulenc)
189 GstEmulEncClass *oclass;
191 oclass = (GstEmulEncClass*) (G_OBJECT_GET_CLASS(emulenc));
193 emulenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
194 gst_pad_set_setcaps_function (emulenc->sinkpad,
195 GST_DEBUG_FUNCPTR(gst_emulenc_setcaps));
196 gst_pad_set_event_function (emulenc->sinkpad,
197 GST_DEBUG_FUNCPTR(gst_emulenc_sink_event));
198 gst_pad_set_chain_function (emulenc->sinkpad,
199 GST_DEBUG_FUNCPTR(gst_emulenc_chain));
200 gst_element_add_pad (GST_ELEMENT(emulenc), emulenc->sinkpad);
202 emulenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src") ;
203 gst_pad_use_fixed_caps (emulenc->srcpad);
204 gst_pad_set_event_function (emulenc->srcpad,
205 GST_DEBUG_FUNCPTR(gst_emulenc_src_event));
206 gst_element_add_pad (GST_ELEMENT(emulenc), emulenc->srcpad);
210 gst_emulenc_finalize (GObject *object)
213 GstEmulEnc *emulenc = (GstEmulEnc *) object;
215 G_OBJECT_CLASS (parent_class)->finalize (object);
219 gst_emulenc_src_event (GstPad *pad, GstEvent *event)
225 gst_emulenc_get_caps (GstEmulEnc *emulenc, GstCaps *caps)
227 GstStructure *structure;
229 int width, height, bits_per_coded_sample;
231 // const GValue *par;
232 // guint extradata_size;
233 // guint8 *extradata;
235 /* FFmpeg Specific Values */
236 const GstBuffer *buf;
239 structure = gst_caps_get_structure (caps, 0);
241 value = gst_structure_get_value (structure, "codec_data");
243 buf = GST_BUFFER_CAST (gst_value_get_mini_object (value));
244 emulenc->extradata_size = GST_BUFFER_SIZE (buf);
245 emulenc->extradata = GST_BUFFER_DATA (buf);
247 CODEC_LOG (2, "no codec data\n");
248 emulenc->extradata_size = 0;
249 emulenc->extradata = NULL;
252 #if 1 /* video type */
253 /* Common Properites, width, height and etc. */
254 gst_structure_get_int (structure, "width", &width);
255 gst_structure_get_int (structure, "height", &height);
256 gst_structure_get_int (structure, "bpp", &bits_per_coded_sample);
258 emulenc->format.video.width = width;
259 emulenc->format.video.height = height;
261 fps = gst_structure_get_value (structure, "framerate");
263 emulenc->format.video.framerate_den = gst_value_get_fraction_numerator (fps);
264 emulenc->format.video.framerate_num = gst_value_get_fraction_denominator (fps);
268 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
270 sample_aspect_ratio.num = gst_structure_get_fraction_numerator (par);
271 sample_aspect_ratio.den = gst_structure_get_fraction_denominator (par);
276 #if 0 /* audio type */
277 gst_structure_get_int (structure, "channels", &channels);
278 gst_structure_get_int (structure, "rate", &sample_rate);
279 gst_structure_get_int (structure, "block_align", &block_align);
280 gst_structure_get_int (structure, "bitrate", &bit_rate);
282 emulenc->format.audio.channels = channels;
283 emulenc->format.audio.samplerate = sample_rate;
289 gst_emulenc_setcaps (GstPad *pad, GstCaps *caps)
292 GstEmulEncClass *oclass;
295 emulenc = (GstEmulEnc *) (gst_pad_get_parent (pad));
296 oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
298 GST_OBJECT_LOCK (emulenc);
300 gst_emulenc_get_caps (emulenc, caps);
303 if (!emulenc->format.video.framerate_den ||
304 !emulenc->format.video.framerate_num) {
305 emulenc->format.video.framerate_num = 1;
306 emulenc->format.video.framerate_den = 25;
310 if (gst_emul_codec_dev_open (emulenc) < 0) {
311 CODEC_LOG(1, "failed to access %s or mmap operation\n", CODEC_DEV);
312 GST_OBJECT_UNLOCK (emulenc);
313 gst_object_unref (emulenc);
317 if (gst_emul_codec_init (emulenc) < 0) {
318 CODEC_LOG(1, "cannot initialize codec\n");
319 GST_OBJECT_UNLOCK (emulenc);
320 gst_object_unref (emulenc);
324 #if 0 /* open a parser */
325 gst_emul_codec_parser (emulenc);
328 GST_OBJECT_UNLOCK (emulenc);
330 gst_object_unref (emulenc);
336 gst_emulenc_sink_event (GstPad *pad, GstEvent *event)
339 gboolean ret = FALSE;
341 emulenc = (GstEmulEnc *) gst_pad_get_parent (pad);
343 switch (GST_TYPE_EVENT (event)) {
345 CODEC_LOG(2, "received GST_EVENT_EOS\n");
347 case GST_EVENT_NEWSEGMENT:
348 CODEC_LOG(2, "received GST_EVENT_NEWSEGMENT\n");
351 ret = gst_pad_push_event (emulenc->srcpad, event);
354 gst_object_unref (emulenc);
360 gst_emulenc_chain (GstPad *pad, GstBuffer *buffer)
363 guint8 *in_buf = NULL;
366 GstClockTime in_timestamp;
367 GstFlowReturn ret = GST_FLOW_OK;
369 emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
371 in_size = GST_BUFFER_SIZE (buffer);
372 in_buf = GST_BUFFER_DATA (buffer);
373 in_timestamp = GST_BUFFER_TIMESTAMP (buffer);
375 gst_emul_codec_encode_video (emulenc, in_buf, in_size, &out_buf, in_timestamp);
377 CODEC_LOG(1, "out_buf:%p, ret:%d\n", out_buf, ret);
379 ret = gst_pad_push (emulenc->srcpad, out_buf);
383 gst_buffer_unref (buffer);
388 static GstStateChangeReturn
389 gst_emulenc_change_state (GstElement *element, GstStateChange transition)
391 GstEmulEnc *emulenc = (GstEmulEnc*)element;
392 GstStateChangeReturn ret;
394 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
396 switch (transition) {
397 case GST_STATE_CHANGE_PAUSED_TO_READY:
398 gst_emul_codec_deinit (emulenc);
407 gst_emulenc_register (GstPlugin *plugin)
409 GTypeInfo typeinfo = {
410 sizeof (GstEmulEncClass),
411 (GBaseInitFunc) gst_emulenc_base_init,
413 (GClassInitFunc) gst_emulenc_class_init,
418 (GInstanceInitFunc) gst_emulenc_init,
423 gint rank = GST_RANK_PRIMARY;
425 /* register element */
427 int codec_fd, codec_cnt = 0;
428 int func_type = CODEC_QUERY;
429 int index = 0, size = 0;
431 CodecInfo *codec_info;
433 codec_fd = open(CODEC_DEV, O_RDWR);
435 perror("failed to open codec device");
439 printf("[codec] fd:%d\n", codec_fd);
440 buf = mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, codec_fd, 0);
442 perror("failed to mmap");
445 printf("[codec] mmap:%p\n", buf);
447 write (codec_fd, &func_type, sizeof(int));
448 memcpy (&codec_cnt, buf, sizeof(int));
449 size = sizeof(uint32_t);
451 codec_info = g_malloc0 (codec_cnt * sizeof(CodecInfo));
452 for (; index < codec_cnt; index++) {
453 memcpy(&codec_info[index].media_type, (uint8_t *)buf + size, sizeof(uint16_t));
454 size += sizeof(uint16_t);
455 memcpy(&codec_info[index].codec_type, (uint8_t *)buf + size, sizeof(uint16_t));
456 size += sizeof(uint16_t);
457 memcpy(&codec_info[index].codec_name, (uint8_t *)buf + size, 32);
459 memcpy(&codec_info[index].codec_longname, (uint8_t *)buf + size, 64);
463 for (index = 0; index < codec_cnt; index++) {
464 if (codec_info[index].codec_type != 0) {
468 type_name = g_strdup_printf ("emulenc_%s", codec_info[index].codec_name);
469 type = g_type_from_name (type_name);
471 type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
472 g_type_set_qdata (type, GST_EMULDEC_PARAMS_QDATA, (gpointer) &codec_info[index]);
475 if (!gst_element_register (plugin, type_name, rank, type)) {
482 printf("[codec] close\n");
490 void *gst_emul_codec_query (GstEmulEnc *emulenc)
495 int func_type = CODEC_QUERY;
496 CodecInfo *codec_info;
498 CODEC_LOG(1, "enter: %s\n", __func__);
500 fd = emulenc->codecbuf.fd;
501 mmapbuf = emulenc->codecbuf.mmapbuf;
503 CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV);
508 CODEC_LOG(1, "failed to get mmaped memory address\n");
512 write (fd, &func_type, sizeof(func_type));
513 memcpy (&codec_cnt, mmapbuf, sizeof(uint32_t));
514 size += sizeof(uint32_t);
516 codec_info = g_malloc0 (codec_cnt * sizeof(CodecInfo));
518 for (i = 0; i < codec_cnt; i++) {
519 memcpy (&codec_info[i].mediatype, (uint8_t *)mmapbuf + size, sizeof(uint16_t));
520 size += sizeof(uint16_t);
521 memcpy (&codec_info[i].codectype, (uint8_t *)mmapbuf + size, sizeof(uint16_t));
522 size += sizeof(uint16_t);
523 memcpy (codec_info[i].name, (uint8_t *)mmapbuf + size, 32);
525 memcpy (codec_info[i].long_name, (uint8_t *)mmapbuf + size, 64);
529 CODEC_LOG(1, "leave: %s\n", __func__);
534 int gst_emul_codec_init (GstEmulEnc *emulenc)
538 guint extradata_size = 0;
539 guint8 *extradata = NULL;
541 int func_type = CODEC_INIT;
543 CODEC_LOG(1, "enter: %s\n", __func__);
545 fd = emulenc->codecbuf.fd;
546 mmapbuf = emulenc->codecbuf.mmapbuf;
548 CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV);
553 CODEC_LOG(1, "failed to get mmaped memory address\n");
557 extradata_size = emulenc->extradata_size;
558 extradata = emulenc->extradata;
560 /* copy basic info to initialize codec on the host side.
561 * e.g. width, height, FPS ant etc. */
562 memcpy ((uint8_t *)mmapbuf, &emulenc->format.video, sizeof(emulenc->format.video));
563 size += sizeof(emulenc->format.video);
565 memcpy ((uint8_t *)mmapbuf + size, &extradata_size, sizeof(extradata_size));
566 size += sizeof(extradata_size);
567 memcpy ((uint8_t *)mmapbuf + size, extradata, extradata_size);
570 ret = write (fd, &func_type, sizeof(func_type));
572 CODEC_LOG(1, "leave: %s\n", __func__);
577 void gst_emul_codec_dev_close (GstEmulEnc *emulenc)
583 CODEC_LOG(1, "enter: %s\n", __func__);
585 fd = emulenc->codecbuf.fd;
586 mmapbuf = emulenc->codecbuf.mmapbuf;
589 CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV);
594 CODEC_LOG(1, "failed to get mmaped memory address\n");
598 CODEC_LOG(2, "release mmaped memory region of %s\n", CODEC_DEV);
599 ret = munmap(mmapbuf, 12 * 4096);
601 CODEC_LOG(1, "failed to release mmaped memory region of %s\n", CODEC_DEV);
604 CODEC_LOG(2, "close %s fd\n", CODEC_DEV);
607 CODEC_LOG(1, "failed to close %s\n", CODEC_DEV);
610 CODEC_LOG(1, "leave: %s\n", __func__);
613 void gst_emul_codec_deinit (GstEmulEnc *emulenc)
616 int func_type = CODEC_DEINIT;
619 CODEC_LOG(1, "enter: %s\n", __func__);
621 fd = emulenc->codecbuf.fd;
622 mmapbuf = emulenc->codecbuf.mmapbuf;
625 CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV);
630 CODEC_LOG(1, "failed to get mmaped memory address\n");
634 ret = write (fd, &func_type, sizeof(func_type));
636 /* close device fd and release mapped memory region */
637 gst_emul_codec_dev_close (emulenc);
639 CODEC_LOG(1, "leave: %s\n", __func__);
642 int gst_emul_codec_encode_video (GstEmulEnc *emulenc, guint8 *in_buf, guint in_size,
643 GstBuffer **out_buf, GstClockTime in_timestamp)
645 int fd, size = 0, ret;
647 int func_type = CODEC_DECODE_VIDEO;
651 CODEC_LOG(1, "enter: %s\n", __func__);
653 fd = emulenc->codecbuf.fd;
654 mmapbuf = emulenc->codecbuf.mmapbuf;
657 CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV);
662 CODEC_LOG(1, "failed to get mmaped memory address\n");
666 memcpy ((uint8_t *)mmapbuf + size, &in_size, sizeof(guint));
667 size += sizeof(guint);
668 memcpy ((uint8_t *)mmapbuf + size, &in_timestamp, sizeof(GstClockTime));
669 size += sizeof(GstClockTime);
670 memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size);
672 /* provide raw image for decoding to qemu */
673 ret = write (fd, &func_type, sizeof(func_type));
676 memcpy (&out_size, (uint8_t *)mmapbuf + size, sizeof(uint));
677 size += sizeof(guint);
679 ret = gst_pad_alloc_buffer_and_set_caps (emulenc->srcpad,
680 GST_BUFFER_OFFSET_NONE, out_size,
681 GST_PAD_CAPS (emulenc->srcpad), out_buf);
683 gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (emulenc->srcpad));
685 if (GST_BUFFER_DATA(*out_buf)) {
686 memcpy (GST_BUFFER_DATA(*out_buf), (uint8_t *)mmapbuf + size, out_size);
688 CODEC_LOG(1, "failed to allocate output buffer\n");
691 CODEC_LOG(1, "leave: %s\n", __func__);
697 void emulenc_encode_audio ()
699 int fd, size = 0, ret;
701 int func_type = CODEC_DECODE_AUDIO;
705 CODEC_LOG(1, "enter: %s\n", __func__);
707 fd = emulenc->codecbuf.fd;
708 mmapbuf = emulenc->codecbuf.mmapbuf;
711 CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV);
716 CODEC_LOG(1, "failed to get mmaped memory address\n");
720 memcpy ((uint8_t *)mmapbuf + size, &in_size, sizeof(guint));
721 size += sizeof(guint);
722 memcpy ((uint8_t *)mmapbuf + size, &in_timestamp, sizeof(GstClockTime));
723 size += sizeof(GstClockTime);
724 memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size);
726 /* provide raw image for decoding to qemu */
727 ret = write (fd, &func_type, sizeof(func_type));
730 memcpy (&out_size, (uint8_t *)mmapbuf + size, sizeof(uint));
731 size += sizeof(guint);
733 *out_buf = gst_buffer_new();
734 GST_BUFFER_DATA (out_buf) = GST_BUFFER_MALLOCDATA (out_buf) = av_malloc (out_size);
735 GST_BUFFER_SIZE (out_buf) = out_size;
736 // GST_BUFFER_FREE_FUNC (out_buf) = av_free;
737 if (GST_PAD_CAPS(emulenc->srcpad)) {
738 gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (emulenc->srcpad));
741 if (GST_BUFFER_DATA(*out_buf)) {
742 memcpy (GST_BUFFER_DATA(*out_buf), (uint8_t *)mmapbuf + size, out_size);
744 CODEC_LOG(1, "failed to allocate output buffer\n");
746 CODEC_LOG(1, "leave: %s\n", __func__);