From: Kitae Kim Date: Wed, 30 Jan 2013 12:30:07 +0000 (+0900) Subject: implemented decoding audio part, but needs to improve. X-Git-Tag: submit/tizen/20150529.014846~46^2~16 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1f93f119af9d31e37cbe693d592259ab2a22e0fb;p=platform%2Fadaptation%2Femulator%2Fgst-plugins-emulator.git implemented decoding audio part, but needs to improve. --- diff --git a/src/Makefile.am b/src/Makefile.am index 8f2bc4b..d4f06f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,9 @@ # Note: plugindir is set in configure ############################################################################## -# TODO: change libgstplugin.la to something else, e.g. libmysomething.la # +# TODO: change libgstemul.la to something else, e.g. libmysomething.la # ############################################################################## -plugin_LTLIBRARIES = libgstplugin.la +plugin_LTLIBRARIES = libgstemul.la ############################################################################## # TODO: for the next set of variables, name the prefix if you named the .la, # @@ -14,13 +14,17 @@ plugin_LTLIBRARIES = libgstplugin.la ############################################################################## # sources used to compile this plug-in -libgstplugin_la_SOURCES = gstplugin.c gstplugin.h +libgstemul_la_SOURCES = gstemul.c \ + gstemulutils.c \ + gstemulnewdec.c \ + gstemulapi.c \ + gstemuldev.c # compiler and linker flags used to compile this plugin, set in configure.ac -libgstplugin_la_CFLAGS = $(GST_CFLAGS) -libgstplugin_la_LIBADD = $(GST_LIBS) -libgstplugin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstplugin_la_LIBTOOLFLAGS = --tag=disable-static +libgstemul_la_CFLAGS = $(GST_CFLAGS) -g +libgstemul_la_LIBADD = $(GST_LIBS) -lgstaudio-0.10 -lgstpbutils-0.10 +libgstemul_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstemul_la_LIBTOOLFLAGS = --tag=disable-static # headers we need but don't want installed -noinst_HEADERS = gstplugin.h +#noinst_HEADERS = gstemul.h diff --git a/src/gstaudiofilter.c b/src/gstaudiofilter.c deleted file mode 100644 index 462b763..0000000 --- a/src/gstaudiofilter.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2003> David Schleef - * Copyright (C) YEAR AUTHOR_NAME AUTHOR_EMAIL - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Alternatively, the contents of this file may be used under the - * GNU Lesser General Public License Version 2.1 (the "LGPL"), in - * which case the following provisions apply instead of the ones - * mentioned above: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:element-plugin - * - * FIXME:Describe plugin here. - * - * - * Example launch line - * |[ - * gst-launch -v -m audiotestsrc ! plugin ! autoaudiosink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -GST_DEBUG_CATEGORY_STATIC (gst_plugin_template_debug); -#define GST_CAT_DEFAULT gst_plugin_template_debug - -typedef struct _GstPluginTemplate GstPluginTemplate; -typedef struct _GstPluginTemplateClass GstPluginTemplateClass; - -#define GST_TYPE_PLUGIN_TEMPLATE \ - (gst_plugin_template_get_type()) -#define GST_PLUGIN_TEMPLATE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLUGIN_TEMPLATE,GstPluginTemplate)) -#define GST_PLUGIN_TEMPLATE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLUGIN_TEMPLATE,GstPluginTemplateClass)) -#define GST_IS_PLUGIN_TEMPLATE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLUGIN_TEMPLATE)) -#define GST_IS_PLUGIN_TEMPLATE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLUGIN_TEMPLATE)) - -struct _GstPluginTemplate -{ - GstAudioFilter audiofilter; -}; - -struct _GstPluginTemplateClass -{ - GstAudioFilterClass parent_class; -}; - - -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0 - /* FILL ME */ -}; - -/* debug category for fltering log messages - * - * FIXME:exchange the string 'Template plugin' with your description - */ -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_plugin_template_debug, "plugin", 0, "Template plugin"); - -GST_BOILERPLATE_FULL (GstPluginTemplate, gst_plugin_template, - GstAudioFilter, GST_TYPE_AUDIO_FILTER, DEBUG_INIT); - -static void gst_plugin_template_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_plugin_template_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -static gboolean gst_plugin_template_setup (GstAudioFilter * filter, - GstRingBufferSpec * spec); -static GstFlowReturn gst_plugin_template_filter (GstBaseTransform * bt, - GstBuffer * outbuf, GstBuffer * inbuf); -static GstFlowReturn -gst_plugin_template_filter_inplace (GstBaseTransform * base_transform, - GstBuffer * buf); - -#define ALLOWED_CAPS_STRING \ - GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS - -/* GObject vmethod implementations */ - -static void -gst_plugin_template_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstAudioFilterClass *audiofilter_class = GST_AUDIO_FILTER_CLASS (klass); - GstCaps *caps; - - gst_element_class_set_details_simple (element_class, - "Plugin", - "Filter/Effect/Audio", - "FIXME:Filters audio", - "AUTHOR_NAME AUTHOR_EMAIL"); - - caps = gst_caps_from_string (ALLOWED_CAPS_STRING); - gst_audio_filter_class_add_pad_templates (audiofilter_class, caps); - gst_caps_unref (caps); -} - -static void -gst_plugin_template_class_init (GstPluginTemplateClass * klass) -{ - GObjectClass *gobject_class; - GstBaseTransformClass *btrans_class; - GstAudioFilterClass *audio_filter_class; - - gobject_class = (GObjectClass *) klass; - btrans_class = (GstBaseTransformClass *) klass; - audio_filter_class = (GstAudioFilterClass *) klass; - -#if 0 - g_object_class_install_property (gobject_class, ARG_METHOD, - g_param_spec_enum ("method", "method", "method", - GST_TYPE_AUDIOTEMPLATE_METHOD, GST_AUDIOTEMPLATE_METHOD_1, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#endif - - gobject_class->set_property = gst_plugin_template_set_property; - gobject_class->get_property = gst_plugin_template_get_property; - - /* this function will be called whenever the format changes */ - audio_filter_class->setup = gst_plugin_template_setup; - - /* here you set up functions to process data (either in place, or from - * one input buffer to another output buffer); only one is required */ - btrans_class->transform = gst_plugin_template_filter; - btrans_class->transform_ip = gst_plugin_template_filter_inplace; -} - -static void -gst_plugin_template_init (GstPluginTemplate * plugin_template, - GstPluginTemplateClass * g_class) -{ - GST_DEBUG ("init"); - - /* do stuff if you need to */ -} - -static void -gst_plugin_template_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstPluginTemplate *filter = GST_PLUGIN_TEMPLATE (object); - - GST_OBJECT_LOCK (filter); - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (filter); -} - -static void -gst_plugin_template_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstPluginTemplate *filter = GST_PLUGIN_TEMPLATE (object); - - GST_OBJECT_LOCK (filter); - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (filter); -} - -static gboolean -gst_plugin_template_setup (GstAudioFilter * filter, - GstRingBufferSpec * spec) -{ - GstPluginTemplate *plugin_template; - - plugin_template = GST_PLUGIN_TEMPLATE (filter); - - /* if any setup needs to be done, do it here */ - - return TRUE; /* it's all good */ -} - -/* You may choose to implement either a copying filter or an - * in-place filter (or both). Implementing only one will give - * full functionality, however, implementing both will cause - * audiofilter to use the optimal function in every situation, - * with a minimum of memory copies. */ - -static GstFlowReturn -gst_plugin_template_filter (GstBaseTransform * base_transform, - GstBuffer * inbuf, GstBuffer * outbuf) -{ - GstPluginTemplate *plugin_template; - GstAudioFilter *audiofilter; - - audiofilter = GST_AUDIO_FILTER (base_transform); - plugin_template = GST_PLUGIN_TEMPLATE (base_transform); - - /* FIXME: do something interesting here. This simply copies the source - * to the destination. */ - - memcpy (GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf), - GST_BUFFER_SIZE (inbuf)); - - return GST_FLOW_OK; -} - -static GstFlowReturn -gst_plugin_template_filter_inplace (GstBaseTransform * base_transform, - GstBuffer * buf) -{ - GstPluginTemplate *plugin_template; - GstAudioFilter *audiofilter; - - audiofilter = GST_AUDIO_FILTER (base_transform); - plugin_template = GST_PLUGIN_TEMPLATE (base_transform); - - /* FIXME: do something interesting here. This simply copies the source - * to the destination. */ - - return GST_FLOW_OK; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "plugin", GST_RANK_NONE, - GST_TYPE_PLUGIN_TEMPLATE); -} - -/* gstreamer looks for this structure to register plugins - * - * FIXME:exchange the string 'Template plugin' with you plugin description - */ -GST_PLUGIN_DEFINE ( - GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "plugin", - "Template plugin", - plugin_init, - VERSION, "LGPL", - "GStreamer", - "http://gstreamer.net/" -); diff --git a/src/gstemul.c b/src/gstemul.c index e94a06b..b682d65 100644 --- a/src/gstemul.c +++ b/src/gstemul.c @@ -1,9 +1,9 @@ /* * Emulator * - * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. * - * Contact: + * Contact: * KiTae Kim * SeokYeon Hwang * YeongKyoon Lee @@ -35,7 +35,7 @@ * */ -#include +#include "gstemulcommon.h" GST_DEBUG_CATEGORY (emul_debug); @@ -50,17 +50,106 @@ GST_DEBUG_CATEGORY (emul_debug); #define GST_IS_EMULDEC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EMULDEC)) -extern gboolean gst_emuldec_register (GstPlugin *plugin); -extern gboolean gst_emulenc_register (GstPlugin *plugin); +gboolean gst_emuldec_register (GstPlugin *plugin, GList *element); +gboolean gst_emulenc_register (GstPlugin *plugin, GList *element); + +static GList *codec_element = NULL; + +static gboolean +gst_emul_codec_element_init () +{ + int fd, size = 0; + int version = 0; + int data_length = 0; + int ret = TRUE; + void *buffer = NULL; + GList *element = NULL; + CodecIOParams params; + + fd = open (CODEC_DEV, O_RDWR); + if (fd < 0) { + perror ("failed to open codec device"); + } + +#if 0 + ioctl (fd, CODEC_CMD_GET_VERSION, &version); + if (version != CODEC_VER) { + printf ("version conflict between device: %d, plugin: %d\n", + version, CODEC_VER); + return FALSE; + } +#endif + + buffer = mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (!buffer) { + perror ("failure memory mapping."); + } + + CODEC_PARAM_INIT (params); + params.api_index = CODEC_ELEMENT_INIT; + CODEC_WRITE_TO_QEMU (fd, ¶ms, 1); + + do { + CodecElement *elm = NULL; + + elm = g_malloc0 (sizeof(CodecElement)); + if (!elm) { + printf ("Failed to allocate memory.\n"); + ret = FALSE; + break; + } + + memcpy (&data_length, (uint8_t *)buffer + size, sizeof(data_length)); + size += sizeof(data_length); + if (!data_length) { +// printf ("There is no more avcodec.\n"); + break; + } + memcpy (elm, (uint8_t *)buffer + size, data_length); + size += data_length; +#if 0 + printf("codec: %s, longname: %s, decode: %d, media: %d\n", + elm->name, elm->longname, elm->codec_type, elm->media_type); +#endif + element = g_list_append (element, elm); + } while (1); + + codec_element = element; + + munmap (buffer, 4096); + close (fd); + + return ret; +} static gboolean plugin_init (GstPlugin *plugin) { - GST_DEBUG_CATEGORY_INIT (emul_debug, "tizen-emul", 0, "Tizen Emulator Codec Elements"); -// gst_emulenc_register (plugin); - gst_emuldec_register (plugin); + GST_DEBUG_CATEGORY_INIT (emul_debug, + "tizen-emul", 0, "Tizen Emulator Codec Elements"); + gboolean ret; + + gst_emul_init_pix_fmt_info (); + + if (!gst_emul_codec_element_init ()) { + GST_ERROR ("failed to get codec elements from QEMU"); + return FALSE; + } + + ret = gst_emuldec_register (plugin, codec_element); + if (!ret) { + GST_ERROR ("failed to register decoder elements"); + return FALSE; + } +#if 0 + ret = gst_emulenc_register (plugin, codec_element); + if (!ret) { + GST_ERROR ("failed to register encoder elements"); + return FALSE; + } +#endif - return TRUE; + return TRUE; } #ifndef PACKAGE @@ -68,13 +157,13 @@ plugin_init (GstPlugin *plugin) #endif GST_PLUGIN_DEFINE ( - GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "tizen-sdk", - "Codecs for Tizen Emulator", - plugin_init, - "0.1.1", - "LGPL", - "Gst-Emul-Codec", - "http://tizen.org" + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "tizen-sdk", + "Codecs for Tizen Emulator", + plugin_init, + "0.1.1", + "LGPL", + "Gst-Emul-Codec", + "http://tizen.org" ) diff --git a/src/gstemulapi.c b/src/gstemulapi.c new file mode 100644 index 0000000..c4cf537 --- /dev/null +++ b/src/gstemulapi.c @@ -0,0 +1,353 @@ +/* + * GStreamer codec plugin for Tizen Emulator. + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * KiTae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include "gstemulcommon.h" +#include "gstemulapi.h" +#include "gstemuldev.h" + +gboolean +emul_avcodec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev) +{ + int fd; + void *mmapbuf; + int size = 0; + gboolean ret = TRUE; + CodecIOParams params; + + printf ("enter: %s\n", __func__); + + fd = dev->fd; + if (fd < 0) { + GST_ERROR ("failed to get %s fd.\n", CODEC_DEV); + return FALSE; + } + + mmapbuf = dev->buf; + if (!mmapbuf) { + GST_ERROR ("failed to get mmaped memory address.\n"); + return FALSE; + } + +// printf("codec_init media_type: %d, codec_type: %d, name: %s\n", +// media_type, codec_type, name); + + /* copy basic info to initialize codec on the host side. + * e.g. width, height, FPS ant etc. */ + memcpy ((uint8_t *)mmapbuf, &codec->media_type, sizeof(codec->media_type)); + size = sizeof(codec->media_type); + memcpy ((uint8_t *)mmapbuf + size, &codec->codec_type, sizeof(codec->codec_type)); + size += sizeof(codec->codec_type); + memcpy ((uint8_t *)mmapbuf + size, codec->name, sizeof(codec->name)); + size += sizeof(codec->name); + + switch (codec->media_type) { + case AVMEDIA_TYPE_VIDEO: + memcpy ((uint8_t *)mmapbuf + size, &ctx->video, sizeof(ctx->video)); + size += sizeof(ctx->video); + break; + case AVMEDIA_TYPE_AUDIO: + memcpy ((uint8_t *)mmapbuf + size, &ctx->audio, sizeof(ctx->audio)); + size += sizeof(ctx->audio); + break; + default: + GST_ERROR ("media type is unknown.\n"); + ret = FALSE; + break; + } + + memcpy ((uint8_t *)mmapbuf + size, &ctx->codecdata_size, sizeof(ctx->codecdata_size)); + size += sizeof(ctx->codecdata_size); + if (ctx->codecdata_size) { + memcpy ((uint8_t *)mmapbuf + size, ctx->codecdata, ctx->codecdata_size); + } + + CODEC_PARAM_INIT (params); + params.api_index = CODEC_INIT; + params.ctx_index = 0; + CODEC_WRITE_TO_QEMU (fd, ¶ms, 1); + + if (codec->media_type == AVMEDIA_TYPE_AUDIO) { + memcpy (&ctx->audio.sample_fmt, + (uint8_t *)mmapbuf, sizeof(ctx->audio.sample_fmt)); + } + ctx->codec = codec; + + printf ("leave: %s\n", __func__); + + return ret; +} + +void +emul_avcodec_deinit (CodecContext *ctx, CodecDevice *dev) +{ + int fd; + void *mmapbuf; + CodecIOParams params; + + printf ("enter: %s\n", __func__); + + fd = dev->fd; + if (fd < 0) { + GST_ERROR ("failed to get %s fd.\n", CODEC_DEV); + return; + } + + mmapbuf = dev->buf; + if (!mmapbuf) { + GST_ERROR ("failed to get mmaped memory address.\n"); + return; + } + + CODEC_PARAM_INIT (params); + params.api_index = CODEC_DEINIT; + params.ctx_index = 0; + CODEC_WRITE_TO_QEMU (fd, ¶ms, 1); + +#if 0 + /* close device fd and release mapped memory region */ + gst_emul_codec_device_close (dev); +#endif + + printf ("leave: %s\n", __func__); +} + +int +emul_avcodec_decode_video (CodecContext *ctx, guint8 *in_buf, guint in_size, + GstBuffer **out_buf, int *got_picture_ptr, CodecDevice *dev) +{ + int fd; + void *mmapbuf; + int len = 0, size = 0; + guint out_size; + CodecIOParams params; + + *out_buf = NULL; + + printf ("enter: %s\n", __func__); + + fd = dev->fd; + if (fd < 0) { + GST_ERROR ("failed to get %s fd\n", CODEC_DEV); + return -1; + } + + mmapbuf = dev->buf; + if (!mmapbuf) { + GST_ERROR ("failed to get mmaped memory address\n"); + return -1; + } + + memcpy ((uint8_t *)mmapbuf, &in_size, sizeof(guint)); + size = sizeof(guint); +// memcpy ((uint8_t *)mmapbuf + size, &dec_info->timestamp, sizeof(GstClockTime)); +// size += sizeof(GstClockTime); + memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size); + + /* provide raw image for decoding to qemu */ + CODEC_PARAM_INIT (params); + params.api_index = CODEC_DECODE_VIDEO; + params.ctx_index = 0; + CODEC_WRITE_TO_QEMU (fd, ¶ms, 1); + + memcpy (&len, (uint8_t *)mmapbuf, sizeof(len)); + size = sizeof(len); + + + printf ("leave: %s\n", __func__); + + return len; +} + +int +emul_avcodec_decode_audio (CodecContext *ctx, int16_t *samples, + gint *frame_size_ptr, guint8 *in_buf, guint in_size, CodecDevice *dev) +{ + int fd; + void *mmapbuf = NULL; + int size = 0; + gint out_size = 0, len; + CodecIOParams params; + + fd = dev->fd; + if (fd < 0) { + GST_ERROR("failed to get %s fd\n", CODEC_DEV); + return -1; + } + + mmapbuf = dev->buf; + if (!mmapbuf) { + GST_ERROR("failed to get mmaped memory address\n"); + return -1; + } + + memcpy ((uint8_t *)mmapbuf, &in_size, sizeof(guint)); + size = sizeof(guint); + if (in_size > 0) { + memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size); + } + + CODEC_PARAM_INIT (params); + params.api_index = CODEC_DECODE_AUDIO; + params.ctx_index = 0; + params.device_mem_offset = 0; + CODEC_WRITE_TO_QEMU (fd, ¶ms, 1); + + memcpy (&ctx->audio.channel_layout, + (uint8_t *)mmapbuf, sizeof(ctx->audio.channel_layout)); + size = sizeof(ctx->audio.channel_layout); + memcpy (&len, (uint8_t *)mmapbuf + size, sizeof(len)); + size += sizeof(len); + memcpy (frame_size_ptr, (uint8_t *)mmapbuf + size, sizeof(*frame_size_ptr)); + size += sizeof(*frame_size_ptr); + if (len > 0) { + memcpy (samples, (uint8_t *)mmapbuf + size, FF_MAX_AUDIO_FRAME_SIZE); + } + + return len; +} + +int +emul_avcodec_encode_video (CodecContext *ctx, guint8 *in_buf, guint in_size, + GstBuffer **out_buf, CodecDevice *dev) +{ + int fd; + void *mmapbuf; + int len = 0, outbuf_size, size = 0; + CodecIOParams params; + + printf ("enter: %s\n", __func__); + + fd = dev->fd; + if (fd < 0) { + GST_ERROR ("failed to get %s fd.\n", CODEC_DEV); + return FALSE; + } + + mmapbuf = dev->buf; + if (!mmapbuf) { + GST_ERROR ("failed to get mmaped memory address.\n"); + return FALSE; + } + + memcpy ((uint8_t *)mmapbuf + size, &in_size, sizeof(guint)); + size += sizeof(guint); +#if 0 + memcpy ((uint8_t *)mmapbuf + size, &in_timestamp, sizeof(GstClockTime)); + size += sizeof(GstClockTime); +#endif + memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size); + + CODEC_PARAM_INIT (params); + params.api_index = CODEC_DECODE_AUDIO; + params.ctx_index = 0; + CODEC_WRITE_TO_QEMU (fd, ¶ms, 1); + +#if 0 + size = 0; + memcpy (&out_size, (uint8_t *)mmapbuf + size, sizeof(uint)); + size += sizeof(guint); + + ret = gst_pad_alloc_buffer_and_set_caps (emulenc->srcpad, + GST_BUFFER_OFFSET_NONE, out_size, + GST_PAD_CAPS (emulenc->srcpad), out_buf); + + gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (emulenc->srcpad)); + + if (GST_BUFFER_DATA(*out_buf)) { + memcpy (GST_BUFFER_DATA(*out_buf), (uint8_t *)mmapbuf + size, out_size); + } else { + pritnf ("failed to allocate output buffer\n"); + } +#endif + + printf ("leave: %s\n", __func__); + + return len; +} + +int +emul_avcodec_encode_audio (CodecContext *ctx, CodecDevice *dev) +{ + int fd; + void *mmapbuf; + int len = 0, size = 0; + CodecIOParams params; + + printf ("enter: %s\n", __func__); + + fd = dev->fd; + if (fd < 0) { + GST_ERROR ("failed to get %s fd.\n", CODEC_DEV); + return FALSE; + } + + mmapbuf = dev->buf; + if (!mmapbuf) { + GST_ERROR ("failed to get mmaped memory address.\n"); + return FALSE; + } + +#if 0 + memcpy ((uint8_t *)mmapbuf + size, &in_size, sizeof(guint)); + size += sizeof(guint); + memcpy ((uint8_t *)mmapbuf + size, &in_timestamp, sizeof(GstClockTime)); + size += sizeof(GstClockTime); + memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size); +#endif + + CODEC_PARAM_INIT (params); + params.api_index = CODEC_DECODE_AUDIO; + params.ctx_index = 0; + CODEC_WRITE_TO_QEMU (fd, ¶ms, 1); + +#if 0 + size = 0; + memcpy (&out_size, (uint8_t *)mmapbuf + size, sizeof(uint)); + size += sizeof(guint); + + *out_buf = gst_buffer_new(); + GST_BUFFER_DATA (out_buf) = GST_BUFFER_MALLOCDATA (out_buf) = av_malloc (out_size); + GST_BUFFER_SIZE (out_buf) = out_size; + // GST_BUFFER_FREE_FUNC (out_buf) = g_free; + if (GST_PAD_CAPS(emulenc->srcpad)) { + gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (emulenc->srcpad)); + } + + if (GST_BUFFER_DATA(*out_buf)) { + memcpy (GST_BUFFER_DATA(*out_buf), (uint8_t *)mmapbuf + size, out_size); + } else { + pritnf ("failed to allocate output buffer\n"); + } +#endif + + printf ("leave: %s\n", __func__); + + return len; +} diff --git a/src/gstemulapi.h b/src/gstemulapi.h new file mode 100644 index 0000000..203d839 --- /dev/null +++ b/src/gstemulapi.h @@ -0,0 +1,48 @@ +/* + * GStreamer codec plugin for Tizen Emulator. + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * KiTae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef __GST_EMUL_API_H__ +#define __GST_EMUL_API_H__ + +#include "gstemulcommon.h" + +gboolean emul_avcodec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev); +int emul_avcdoec_deinit (CodecContext *ctx, CodecDevice *dev); + +int emul_avcodec_decode_video (CodecContext *ctx, guint8 *in_buf, guint in_size, + GstBuffer **out_buf, int *got_picture_ptr, CodecDevice *dev); +int emul_avcodec_decode_audio (CodecContext *ctx, int16_t *samples, + gint *frame_size_ptr, guint8 *in_buf, guint in_size, CodecDevice *dev); + +int emul_avcodec_encode_video (CodecContext *ctx, guint8 *in_buf, guint in_size, + GstBuffer **out_buf, CodecDevice *dev); +int emul_avcodec_encode_audio (CodecContext *ctx, CodecDevice *dev); + +#endif /* __GST_EMUL_API_H__ */ diff --git a/src/gstemulcommon.h b/src/gstemulcommon.h index 46af0fd..67c97e4 100644 --- a/src/gstemulcommon.h +++ b/src/gstemulcommon.h @@ -1,3 +1,33 @@ +/* + * GStreamer codec plugin for Tizen Emulator. + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * KiTae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + #ifndef __GST_EMUL_H__ #define __GST_EMUL_H__ @@ -7,40 +37,89 @@ #include #include #include +#include #include +#include #include +#include "pixfmt.h" GST_DEBUG_CATEGORY_EXTERN (emul_debug); -#define GST_CAT_DEFAULT emul_debug +#define GST_CAT_DEFAULT emul_debug G_BEGIN_DECLS -static int codec_debug_level = 2; -#define CODEC_LOG(level, fmt, ...) \ - do { \ - if (codec_debug_level >= (level)) \ - printf("[gst-ffmpeg-emul][%d] " fmt, __LINE__, ##__VA_ARGS__); \ - } while (0) - -#define CODEC_DEV "/dev/codec" +#define CODEC_DEV "/dev/newcodec" #define CODEC_VER 10 -typedef struct CodecDev -{ - int fd; - void *buffer; -} CodecDev; +#define CODEC_PARAM_INIT(var) \ + memset (&var, 0x00, sizeof(var)) + +#define CODEC_WRITE_TO_QEMU(fd, var, size) \ + if (write (fd, var, size) < 0) { \ + printf ("[%d] failed to copy data.\n", __LINE__); \ + } + +#define FF_INPUT_BUFFER_PADDING_SIZE 8 +#define FF_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio +#define FF_MIN_BUFFER_SIZE 16384 + +typedef struct _CodecIOParams { + uint32_t api_index; + uint32_t ctx_index; + uint32_t file_index; + uint32_t mem_index; + uint32_t device_mem_offset; +} CodecIOParams; + +typedef struct _CodecDevice { + int fd; + void *buf; + uint32_t buf_size; +} CodecDevice; + +typedef struct _CodecElement { + gchar name[32]; + gchar longname[64]; + uint16_t codec_type; + uint16_t media_type; +#if 0 + union { + struct { + int8_t pix_fmts[8]; + } video; + struct { + int8_t sample_fmts[8]; + } audio; + } format; +#endif +} CodecElement; -typedef struct _CodecInfo { - uint16_t media_type; - uint16_t codec_type; - gchar codec_name[32]; - gchar codec_longname[64]; - int8_t sample_fmts[8]; -} CodecInfo; +typedef struct _VideoData { + int width, height; + int fps_n, fps_d; + int par_n, par_d; + int pix_fmt, bpp; +} VideoData; + +typedef struct _AudioData { + int channels, sample_rate; + int bit_rate, block_align; + int depth, sample_fmt; + int64_t channel_layout; +} AudioData; + +typedef struct _CodecContext { + uint8_t *codecdata; + int codecdata_size; + + VideoData video; + AudioData audio; + + CodecElement *codec; +} CodecContext; enum CODEC_FUNC_TYPE { - CODEC_QUERY = 1, + CODEC_ELEMENT_INIT = 1, CODEC_INIT, CODEC_DEINIT, CODEC_DECODE_VIDEO, @@ -49,12 +128,26 @@ enum CODEC_FUNC_TYPE { CODEC_ENCODE_AUDIO, }; +enum CODEC_IO_CMD { + CODEC_CMD_GET_VERSION = 5, + CODEC_CMD_GET_DEVICE_MEM, + CODEC_CMD_SET_DEVICE_MEM, + CODEC_CMD_GET_MMAP_OFFSET, + CODEC_CMD_SET_MMAP_OFFSET, +}; + enum CODEC_MEDIA_TYPE { AVMEDIA_TYPE_UNKNOWN = -1, AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, }; +enum CODEC_TYPE { + CODEC_TYPE_UNKNOWN = -1, + CODEC_TYPE_DECODE, + CODEC_TYPE_ENCODE, +}; + enum SAMPLT_FORMAT { SAMPLE_FMT_NONE = -1, SAMPLE_FMT_U8, @@ -69,7 +162,7 @@ enum SAMPLT_FORMAT { * e.g. FFmpeg, x264, libvpx and etc. */ enum { - FFMPEG_TYPE = 1, + FFMPEG_TYPE = 1, }; G_END_DECLS diff --git a/src/gstemuldec.c b/src/gstemuldec.c deleted file mode 100644 index 1cd538a..0000000 --- a/src/gstemuldec.c +++ /dev/null @@ -1,1585 +0,0 @@ -/* - * Emulator - * - * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: - * KiTae Kim - * SeokYeon Hwang - * YeongKyoon Lee - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* First, include the header file for the plugin, to bring in the - * object definition and other useful things. - */ - -/* - * - * Contributors: - * - S-Core Co., Ltd - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -//#include -//#include -#include "gstemulcommon.h" - -#define GST_EMULDEC_PARAMS_QDATA g_quark_from_static_string("emuldec-params") - -typedef struct -{ - gint idx; - GstClockTime timestamp; - GstClockTime duration; - gint64 offset; -} GstTSInfo; - -#define GST_TS_INFO_NONE &ts_info_none -static const GstTSInfo ts_info_none = { -1, -1, -1, -1 }; - -#define MAX_TS_MASK 0xff - -typedef struct _GstEmulDec -{ - GstElement element; - - GstPad *srcpad; - GstPad *sinkpad; - - union { - struct { - gint width; - gint height; - gint framerate_num; - gint framerate_den; - gint pix_fmt; - } video; - struct { - gint channels; - gint samplerate; - gint depth; - } audio; - } format; - - guint extradata_size; - guint8 *extradata; - - GstTSInfo ts_info[MAX_TS_MASK + 1]; - gint ts_idx; - - CodecDev codecbuf; - CodecInfo *codecinfo; -} GstEmulDec; - -typedef struct _GstEmulDecClass -{ - GstElementClass parent_class; - - CodecInfo *codecinfo; - GstPadTemplate *sinktempl; - GstPadTemplate *srctempl; -} GstEmulDecClass; - - -static GstElementClass *parent_class = NULL; - -static void gst_emuldec_base_init (GstEmulDecClass *klass); -static void gst_emuldec_class_init (GstEmulDecClass *klass); -static void gst_emuldec_init (GstEmulDec *emuldec); -static void gst_emuldec_finalize (GObject *object); - -static gboolean gst_emuldec_setcaps (GstPad *pad, GstCaps *caps); - -// sinkpad -static gboolean gst_emuldec_sink_event (GstPad *pad, GstEvent *event); -static GstFlowReturn gst_emuldec_chain (GstPad *pad, GstBuffer *buffer); - -// srcpad -static gboolean gst_emuldec_src_event (GstPad *pad, GstEvent *event); -static GstStateChangeReturn gst_emuldec_change_state (GstElement *element, - GstStateChange transition); - -int gst_emul_codec_init (GstEmulDec *emuldec, CodecInfo *codec_info); -void gst_emul_codec_deinit (GstEmulDec *emuldec); -int gst_emul_decode_video (GstEmulDec *emuldec, guint8 *in_buf, guint in_size, - GstBuffer **out_buf, GstTSInfo *dec_info); -int gst_emul_decode_audio (GstEmulDec *emuldec, guint8 *in_buf, guint in_size, - GstBuffer **outb_buf, GstTSInfo *dec_info); -int gst_emul_codec_device_open (GstEmulDec *emuldec); -int gst_emul_codec_device_close (GstEmulDec *emuldec); - -GstCaps *gst_emul_codecname_to_caps (CodecInfo *info); -GstCaps *gst_emul_codectype_to_video_caps (CodecInfo *info); -GstCaps *gst_emul_codectype_to_audio_caps (CodecInfo *info); -static GstCaps * gst_emul_smpfmt_to_caps (int8_t sample_fmt, CodecInfo *info); - -static gboolean gst_emuldec_negotiate (GstEmulDec *dec, gboolean force); - - -static CodecInfo *codec; - -static const GstTSInfo * -gst_ts_info_store (GstEmulDec *dec, GstClockTime timestamp, - GstClockTime duration, gint64 offset) -{ - gint idx = dec->ts_idx; - dec->ts_info[idx].idx = idx; - dec->ts_info[idx].timestamp = timestamp; - dec->ts_info[idx].duration = duration; - dec->ts_info[idx].offset = offset; - dec->ts_idx = (idx + 1) & MAX_TS_MASK; - - return &dec->ts_info[idx]; -} - -static const GstTSInfo * -gst_ts_info_get (GstEmulDec *dec, gint idx) -{ - if (G_UNLIKELY (idx < 0 || idx > MAX_TS_MASK)) - return GST_TS_INFO_NONE; - - return &dec->ts_info[idx]; -} - -/* - * Implementation - */ -static void -gst_emuldec_base_init (GstEmulDecClass *klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *sinkcaps, *srccaps; - GstPadTemplate *sinktempl, *srctempl; - CodecInfo *info; - gchar *longname, *classification; - - info = - (CodecInfo *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), - GST_EMULDEC_PARAMS_QDATA); - - longname = g_strdup_printf ("%s Decoder", info->codec_longname); - - classification = g_strdup_printf ("Codec/Decoder/%s", - (info->media_type == AVMEDIA_TYPE_VIDEO) ? - "Video" : "Audio"); - - gst_element_class_set_details_simple (element_class, - longname, // longname - classification, // classification - "accelerated codec for Tizen Emulator", // description - "Kitae Kim "); // author - - g_free (longname); - g_free (classification); - -#if 0 - sinkcaps = gst_caps_new_simple (mimetype, - "width", GST_TYPE_INT_RANGE, 16, 4096, - "height", GST_TYPE_INT_RANGE, 16, 4096, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); -#endif - sinkcaps = gst_emul_codecname_to_caps (info); - if (!sinkcaps) { - sinkcaps = gst_caps_from_string ("unknown/unknown"); - } - - // if type is video - switch (info->media_type) { - case AVMEDIA_TYPE_VIDEO: - srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv"); - break; - case AVMEDIA_TYPE_AUDIO: - srccaps = gst_emul_codectype_to_audio_caps (info); - break; - default: - GST_LOG("unknown media type.\n"); - break; - } - - if (!srccaps) { - srccaps = gst_caps_from_string ("unknown/unknown"); - } - - sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, - GST_PAD_ALWAYS, sinkcaps); - srctempl = gst_pad_template_new ("src", GST_PAD_SRC, - GST_PAD_ALWAYS, srccaps); - - gst_element_class_add_pad_template (element_class, srctempl); - gst_element_class_add_pad_template (element_class, sinktempl); - - klass->codecinfo = info; - - klass->sinktempl = sinktempl; - klass->srctempl = srctempl; -} - -static void -gst_emuldec_class_init (GstEmulDecClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - -#if 0 - gobject_class->set_property = gst_emuldec_set_property - gobject_class->get_property = gst_emuldec_get_property -#endif - - gobject_class->finalize = gst_emuldec_finalize; - gstelement_class->change_state = gst_emuldec_change_state; -} - -static void -gst_emuldec_init (GstEmulDec *emuldec) -{ - GstEmulDecClass *oclass; - - oclass = (GstEmulDecClass*) (G_OBJECT_GET_CLASS(emuldec)); - - emuldec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); - gst_pad_set_setcaps_function (emuldec->sinkpad, - GST_DEBUG_FUNCPTR(gst_emuldec_setcaps)); - gst_pad_set_event_function (emuldec->sinkpad, - GST_DEBUG_FUNCPTR(gst_emuldec_sink_event)); - gst_pad_set_chain_function (emuldec->sinkpad, - GST_DEBUG_FUNCPTR(gst_emuldec_chain)); - gst_element_add_pad (GST_ELEMENT(emuldec), emuldec->sinkpad); - - emuldec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src") ; - gst_pad_use_fixed_caps (emuldec->srcpad); - gst_pad_set_event_function (emuldec->srcpad, - GST_DEBUG_FUNCPTR(gst_emuldec_src_event)); - gst_element_add_pad (GST_ELEMENT(emuldec), emuldec->srcpad); -} - -static void -gst_emuldec_finalize (GObject *object) -{ - // Deinit Decoder - GstEmulDec *emuldec = (GstEmulDec *) object; - - if (emuldec->extradata) { - printf("free extradata.\n"); - g_free(emuldec->extradata); - emuldec->extradata = NULL; - } - - if (codec) { - printf("free CodecInfo.\n"); - g_free(codec); - codec = NULL; - } - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_emuldec_src_event (GstPad *pad, GstEvent *event) -{ - GstEmulDec *emuldec; - gboolean res; - - emuldec = (GstEmulDec *) gst_pad_get_parent (pad); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_QOS: - { - gdouble proportion; - GstClockTimeDiff diff; - GstClockTime timestamp; - - gst_event_parse_qos (event, &proportion, &diff, ×tamp); - GST_LOG_OBJECT (emuldec, "update QOS: %f, %" GST_TIME_FORMAT, - proportion, GST_TIME_ARGS (timestamp)); - /* update our QoS values */ -// gst_ffmpegdec_update_qos (ffmpegdec, proportion, timestamp + diff); - - /* forward upstream */ - res = gst_pad_push_event (emuldec->sinkpad, event); - break; - } - default: - /* forward upstream */ - res = gst_pad_push_event (emuldec->sinkpad, event); - break; - } - - gst_object_unref (emuldec); - - return 0; -} - -#if 0 -GstCaps* -gst_emul_codectype_to_video_caps (CodecInfo *info) -{ - GstCaps *caps; - - return caps; -} -#endif - -static GstCaps* -gst_emul_codectype_to_caps (GstEmulDec *emuldec, CodecInfo *codec_info) -{ - GstCaps *caps; - guint32 fmt = 0; - - switch (codec_info->media_type) { - case AVMEDIA_TYPE_VIDEO: - { - const char *mimetype = "video/x-raw-yuv"; - gint num, denom; - - - // YUV420P or YUVJ420P - fmt = GST_MAKE_FOURCC ('I', '4', '2', '0'); - - caps = gst_caps_new_simple (mimetype, - "width", G_TYPE_INT, emuldec->format.video.width, - "height", G_TYPE_INT, emuldec->format.video.height, NULL); - - num = emuldec->format.video.framerate_den; - denom = emuldec->format.video.framerate_num; - - if (!denom) { - GST_LOG ("invalid framerate: %d/0, -> %d/1", num, num); - denom = 1; - } - - if (gst_util_fraction_compare (num, denom, 1000, 1) > 0) { - GST_LOG ("excessive framerate: %d/%d, -> 0/1", num, denom); - num = 0; - denom = 1; - } - - GST_LOG ("setting framerate: %d/%d", num, denom); - gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, denom, NULL); - - // default unfixed setting - if (!caps) { - caps = gst_caps_new_simple (mimetype, - "width", GST_TYPE_INT_RANGE, 16, 4096, - "height", GST_TYPE_INT_RANGE, 16, 4096, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - } - - gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, fmt, NULL); - } - break; - case AVMEDIA_TYPE_AUDIO: - { - const char *mimetype="audio/x-raw-int"; - - caps = gst_caps_new_simple (mimetype, - "rate", G_TYPE_INT, emuldec->format.audio.samplerate, - "channels", G_TYPE_INT, emuldec->format.audio.channels, - "signed", G_TYPE_BOOLEAN, TRUE, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, NULL); - } - break; - default: - break; - } - - return caps; -} - -static void -gst_emul_caps_with_codecid (GstEmulDec *emuldec, - CodecInfo *codec_info, - GstCaps *caps) -{ - GstStructure *structure; - - int width, height, bits_per_coded_sample; - const GValue *fps; - // const GValue *par; - // guint extradata_size; - // guint8 *extradata; - - /* FFmpeg Specific Values */ - const GstBuffer *buf; - const GValue *value; - - structure = gst_caps_get_structure (caps, 0); - - value = gst_structure_get_value (structure, "codec_data"); - if (value) { - buf = GST_BUFFER_CAST (gst_value_get_mini_object (value)); - emuldec->extradata_size = GST_BUFFER_SIZE (buf); - emuldec->extradata = GST_BUFFER_DATA (buf); - printf("extradata: %p, size: %d\n", emuldec->extradata, emuldec->extradata_size); - } else { -// CODEC_LOG(2, "no codec data\n"); - GST_DEBUG_OBJECT (emuldec, "no extra data.\n"); - emuldec->extradata_size = 0; - emuldec->extradata = g_malloc0 (GST_ROUND_UP_16(8)); - } - - printf("caps_with_codecid, media_type: %d, codec_name: %s\n", codec_info->media_type, codec_info->codec_name); - - if (!gst_caps_is_fixed (caps)) { - return; - } - - switch (codec_info->media_type) { - case AVMEDIA_TYPE_VIDEO: - /* Common Properites, width, height and etc. */ - gst_structure_get_int (structure, "width", &width); - gst_structure_get_int (structure, "height", &height); - gst_structure_get_int (structure, "bpp", &bits_per_coded_sample); - - emuldec->format.video.width = width; - emuldec->format.video.height = height; - - fps = gst_structure_get_value (structure, "framerate"); - if (fps) { - emuldec->format.video.framerate_den = gst_value_get_fraction_numerator (fps); - emuldec->format.video.framerate_num = gst_value_get_fraction_denominator (fps); - printf ("framerate: %d/%d.\n", emuldec->format.video.framerate_num, emuldec->format.video.framerate_den); - - } - -#if 0 - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - if (par) { - sample_aspect_ratio.num = gst_structure_get_fraction_numerator (par); - sample_aspect_ratio.den = gst_structure_get_fraction_denominator (par); - } -#endif - break; - /* audio type */ - case AVMEDIA_TYPE_AUDIO: - { - GstStructure *structure; - int channels = 0; - int sample_rate = 0; - int block_align = 0; - int bit_rate = 0; - - g_return_if_fail (gst_caps_get_size (caps) == 1); - structure = gst_caps_get_structure (caps, 0); - - gst_structure_get_int (structure, "channels", &channels); - gst_structure_get_int (structure, "rate", &sample_rate); - gst_structure_get_int (structure, "block_align", &block_align); - gst_structure_get_int (structure, "bitrate", &bit_rate); - - printf("channels: %d, sample_rate: %d, block_align: %d, bit_rate: %d\n", - channels, sample_rate, block_align, bit_rate); - - emuldec->format.audio.channels = channels; - emuldec->format.audio.samplerate = sample_rate; - } - break; - default: - break; - } - -} - -static gboolean -gst_emuldec_setcaps (GstPad *pad, GstCaps *caps) -{ - GstEmulDec *emuldec; - GstEmulDecClass *oclass; - gboolean ret = TRUE; - - emuldec = (GstEmulDec *) (gst_pad_get_parent (pad)); - oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); - - GST_OBJECT_LOCK (emuldec); - - emuldec->codecinfo = oclass->codecinfo; - printf("setcaps, codec_type: %d, codec_name: %s\n", emuldec->codecinfo->codec_type, emuldec->codecinfo->codec_name); - - gst_emul_caps_with_codecid (emuldec, oclass->codecinfo, caps); - -#if 0 - if (!emuldec->format.video.framerate_den || - !emuldec->format.video.framerate_num) { - emuldec->format.video.framerate_num = 1; - emuldec->format.video.framerate_den = 25; - } -#endif - - if (gst_emul_codec_device_open (emuldec) < 0) { -// CODEC_LOG(1, "failed to access %s or mmap operation\n", CODEC_DEV); - GST_LOG_OBJECT (emuldec, "failed to access %s or mmap operation\n", CODEC_DEV); - GST_OBJECT_UNLOCK (emuldec); - gst_object_unref (emuldec); - return FALSE; - } - - if (gst_emul_codec_init (emuldec, oclass->codecinfo) < 0) { -// CODEC_LOG(1, "cannot initialize codec\n"); - GST_LOG_OBJECT (emuldec, "cannot initialize codec.\n"); - GST_OBJECT_UNLOCK (emuldec); - gst_object_unref (emuldec); - return FALSE; - } - -#if 0 /* open a parser */ - gst_emul_codec_parser (emuldec); -#endif - - GST_OBJECT_UNLOCK (emuldec); - - gst_object_unref (emuldec); - - return ret; -} - -static gboolean -gst_emuldec_sink_event (GstPad *pad, GstEvent *event) -{ - GstEmulDec *emuldec; - gboolean ret = FALSE; - - emuldec = (GstEmulDec *) gst_pad_get_parent (pad); -#if 1 - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: -// CODEC_LOG(1, "received GST_EVENT_EOS\n"); - GST_LOG_OBJECT (emuldec, "received GST_EVENT_EOS\n"); - break; - case GST_EVENT_NEWSEGMENT: -// CODEC_LOG(1, "received GST_EVENT_NEWSEGMENT\n"); - GST_LOG_OBJECT (emuldec, "received GST_EVENT_NEWSEGMENT\n"); - break; - } - ret = gst_pad_push_event (emuldec->srcpad, event); -#endif - - gst_object_unref (emuldec); - - return ret; -} - -static GstFlowReturn -gst_emuldec_chain (GstPad *pad, GstBuffer *buffer) -{ - GstEmulDec *emuldec; - CodecInfo *codec_info; - guint8 *in_buf, *aud_buf; - GstBuffer *out_buf = NULL; - gint in_size = 0, aud_size = 0, len = 0; - GstFlowReturn ret = GST_FLOW_OK; - GstClockTime in_timestamp; - GstClockTime in_duration; - gint64 in_offset; - gboolean discont; - const GstTSInfo *in_info; - GstTSInfo *dec_info; - - emuldec = (GstEmulDec *) (GST_PAD_PARENT (pad)); - if (!emuldec) { - GST_ERROR ("failed to get GstEmulDec.\n"); - return GST_FLOW_ERROR; - } - - discont = GST_BUFFER_IS_DISCONT (buffer); - if (G_UNLIKELY (discont)) { - printf("received DISCONT.\n"); - // TODO - // drain - // flush pcache - // flush buffers - // reset timestamp - } - - codec_info = emuldec->codecinfo; - - aud_size = in_size = GST_BUFFER_SIZE (buffer); - aud_buf = in_buf = GST_BUFFER_DATA (buffer); - - in_timestamp = GST_BUFFER_TIMESTAMP (buffer); - in_duration = GST_BUFFER_DURATION (buffer); - in_offset = GST_BUFFER_OFFSET (buffer); - - GST_LOG_OBJECT(emuldec, "offset %" G_GUINT64_FORMAT ", ts: %." GST_TIME_FORMAT "\n", - in_offset, GST_TIME_ARGS(in_timestamp)); - in_info = gst_ts_info_store (emuldec, in_timestamp, in_duration, in_offset); - - // TODO - dec_info = in_info; - - do { - printf("media_type: %d, name: %s\n", codec_info->media_type, codec_info->codec_name); - switch (codec_info->media_type) { - case AVMEDIA_TYPE_VIDEO: -#if 1 - { - /* Caps negotiation */ - GstCaps *caps; - - caps = gst_emul_codectype_to_caps (emuldec, codec_info); - - if (!gst_pad_set_caps (emuldec->srcpad, caps)) { - GST_ERROR_OBJECT(emuldec, "failed to set caps for srcpad.\n"); - gst_buffer_unref (buffer); - return GST_FLOW_NOT_NEGOTIATED; - } - } -#endif - printf("before decode\n"); - len = gst_emul_decode_video (emuldec, in_buf, in_size, &out_buf, dec_info); - printf("after decode\n"); - break; - case AVMEDIA_TYPE_AUDIO: - len = gst_emul_decode_audio (emuldec, in_buf, in_size, &out_buf, dec_info); - aud_size -= len; - aud_buf += len; - break; - default: - break; - } - } while (aud_size > 0); - - GST_DEBUG_OBJECT(emuldec, "out_buf:%p, len:%d\n", out_buf, len); - -#if 0 - idx = picture->reordered_opaque; - out_info = gst_ts_info_get(emuldec, idx); - out_pts = out_info->timestamp; - out_duration = out_info->duration; - out_offset = out_info->offset; - GST_LOG_OBJECT (emuldec, "offset %" G_GUINT64_FORMAT ", ts: %." G_GINT64_FORMAT "\n", - out_offset, out_duration); -#endif - ret = gst_pad_push (emuldec->srcpad, out_buf); - -// g_free (out_buf); - gst_buffer_unref (buffer); - - return ret; -} - -static GstStateChangeReturn -gst_emuldec_change_state (GstElement *element, GstStateChange transition) -{ - GstEmulDec *emuldec = (GstEmulDec*)element; - GstStateChangeReturn ret; - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_emul_codec_deinit (emuldec); - default: - break; - } - - return ret; -} - -gboolean -gst_emuldec_register (GstPlugin *plugin) -{ - GTypeInfo typeinfo = { - sizeof (GstEmulDecClass), - (GBaseInitFunc) gst_emuldec_base_init, - NULL, - (GClassInitFunc) gst_emuldec_class_init, - NULL, - NULL, - sizeof (GstEmulDec), - 0, - (GInstanceInitFunc) gst_emuldec_init, - }; - - GType type; - gchar *type_name; - gint rank = GST_RANK_PRIMARY; - - /* register element */ - { - int codec_fd, codec_cnt = 0; - int func_type = CODEC_QUERY; - int index = 0, size = 0; - uint16_t codec_name_len, codec_longname_len; - void *buf; - CodecInfo *codec_info; - - codec_fd = open(CODEC_DEV, O_RDWR); - if (codec_fd < 0) { - perror("[gst-emul-codec] failed to open codec device"); - return FALSE; - } - - buf = mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, codec_fd, 0); - if (!buf) { - perror("[gst-emul-codec] failed to mmap"); - } - - write (codec_fd, &func_type, sizeof(int)); - memcpy (&codec_cnt, buf, sizeof(int)); - size = sizeof(uint32_t); - - codec_info = g_malloc0 (codec_cnt * sizeof(CodecInfo)); - codec = codec_info; - for (; index < codec_cnt; index++) { - memcpy(&codec_info[index].media_type, (uint8_t *)buf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy(&codec_info[index].codec_type, (uint8_t *)buf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy(&codec_name_len, (uint8_t *)buf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy(&codec_longname_len, (uint8_t *)buf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy(&codec_info[index].codec_name, (uint8_t *)buf + size, codec_name_len); - size += 32; - memcpy(&codec_info[index].codec_longname, (uint8_t *)buf + size, codec_longname_len); - size += 64; - memcpy (&codec_info[index].sample_fmts, (uint8_t *)buf + size, 8); - size += 8; - } - - for (index = 0; index < codec_cnt; index++) { - if (!codec_info[index].codec_type) { - continue; - } - - type_name = g_strdup_printf ("tzdec_%s", codec_info[index].codec_name); - type = g_type_from_name (type_name); - if (!type) { - type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0); - g_type_set_qdata (type, GST_EMULDEC_PARAMS_QDATA, (gpointer) &codec_info[index]); - } - - if (!gst_element_register (plugin, type_name, rank, type)) { - g_free (type_name); - return FALSE; - } - g_free (type_name); - } - - munmap (buf, 4096); - close (codec_fd); - } - - return TRUE; -} - -#if 0 -void *gst_emul_codec_query (GstEmulDec *emuldec) -{ - int fd, codec_cnt = 0; - int size = 0, i; - void *mmapbuf; - int func_type = CODEC_QUERY; - CodecInfo *codec_info; - - CODEC_LOG(2, "enter: %s\n", __func__); - - fd = emuldec->codecbuf.fd; - mmapbuf = emuldec->codecbuf.mmapbuf; - if (fd < 0) { -// CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV); - GST_ERROR_OBJECT(emuldec, "failed to get %s fd.\n", CODEC_DEV); - return NULL; - } - - if (!mmapbuf) { -// CODEC_LOG(1, "failed to get mmaped memory address\n"); - GST_ERROR_OBJECT(emuldec, "failed to get mmaped memory address.\n"); - return NULL; - } - - write (fd, &func_type, sizeof(func_type)); - - memcpy (&codec_cnt, mmapbuf, sizeof(uint32_t)); - size += sizeof(uint32_t); - codec_info = g_malloc0 (codec_cnt * sizeof(CodecInfo)); - - for (i = 0; i < codec_cnt; i++) { - uint16_t codec_name_len, codec_longname_len; - - memcpy (&codec_info[i].media_type, (uint8_t *)mmapbuf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy (&codec_info[i].codec_type, (uint8_t *)mmapbuf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy (&codec_name_len, (uint8_t *)mmapbuf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy (&codec_longname_len, (uint8_t *)mmapbuf + size, sizeof(uint16_t)); - size += sizeof(uint16_t); - memcpy (codec_info[i].codec_name, (uint8_t *)mmapbuf + size, codec_name_len); - size += 32; - memcpy (codec_info[i].codec_longname, (uint8_t *)mmapbuf + size, codec_longname_len); - size += 64; - memcpy (&codec_info[i].sample_fmts, (uint8_t *)mmapbuf + size, 8); - size += 8; - } - - CODEC_LOG(2, "leave: %s\n", __func__); - - return codec_info; -} -#endif - -int gst_emul_codec_device_open (GstEmulDec *emuldec) -{ - int fd; - int width, height; - void *mmapbuf; - uint32_t bufsize; - - CODEC_LOG(2, "enter: %s\n", __func__); - - width = emuldec->format.video.width; - height = emuldec->format.video.height; - bufsize = ((width * height * 3) / 2) + 32; - - if ((fd = open(CODEC_DEV, O_RDWR)) < 0) { - perror("[gst-emul-codec] failed to open codec device"); -// CODEC_LOG(1, "failed to open %s, fd:%d, err:%d\n", CODEC_DEV, fd, errno); - GST_ERROR("failed to open %s, fd:%d, err:%d\n", CODEC_DEV, fd, errno); - - return -1; - } -// CODEC_LOG(2, "succeeded to open %s, ret:%d\n", CODEC_DEV, fd); - GST_DEBUG("succeeded to open %s.\n", CODEC_DEV); - - mmapbuf = mmap (NULL, bufsize, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (!mmapbuf) { -// CODEC_LOG(1, "failure mmap() func\n"); - perror("[gst-emul-codec] failed to map memory with codec device."); - GST_ERROR("failure mmap() func.\n"); - return -1; - } - - emuldec->codecbuf.fd = fd; - emuldec->codecbuf.buffer = mmapbuf; - - return 0; -} - -int gst_emul_codec_init (GstEmulDec *emuldec, CodecInfo *codecinfo) -{ - int fd; - int size = 0, ret; - guint extradata_size = 0; - guint8 *extradata = NULL; - void *mmapbuf; - int func_type = CODEC_INIT; - - CODEC_LOG(2, "enter: %s\n", __func__); - - fd = emuldec->codecbuf.fd; - if (fd < 0) { - GST_ERROR_OBJECT(emuldec, "failed to get %s fd.\n", CODEC_DEV); - return -1; - } - - mmapbuf = emuldec->codecbuf.buffer; - if (!mmapbuf) { - GST_ERROR_OBJECT(emuldec, "failed to get mmaped memory address.\n"); - return -1; - } - - extradata_size = emuldec->extradata_size; - extradata = emuldec->extradata; - - GST_DEBUG_OBJECT(emuldec, "extradata: %p, extradata_size: %d\n", extradata, extradata_size); - - /* copy basic info to initialize codec on the host side. - * e.g. width, height, FPS ant etc. */ - memcpy ((uint8_t *)mmapbuf, &codecinfo->media_type, sizeof(codecinfo->media_type)); - size = sizeof(codecinfo->media_type); - memcpy ((uint8_t *)mmapbuf + size, &codecinfo->codec_type, sizeof(codecinfo->codec_type)); - size += sizeof(codecinfo->codec_type); - memcpy ((uint8_t *)mmapbuf + size, codecinfo->codec_name, sizeof(codecinfo->codec_name)); - size += sizeof(codecinfo->codec_name); - - if (codecinfo->media_type == AVMEDIA_TYPE_VIDEO) { - memcpy ((uint8_t *)mmapbuf + size, &emuldec->format.video, sizeof(emuldec->format.video)); - size += sizeof(emuldec->format.video); - } else if (codecinfo->media_type == AVMEDIA_TYPE_AUDIO) { - memcpy ((uint8_t *)mmapbuf + size, &emuldec->format.audio, sizeof(emuldec->format.audio)); - size += sizeof(emuldec->format.audio); - } else { - GST_ERROR_OBJECT(emuldec, "media type is unknown.\n"); - return -1; - } - - if (extradata) { - memcpy ((uint8_t *)mmapbuf + size, &extradata_size, sizeof(extradata_size)); - size += sizeof(extradata_size); - memcpy ((uint8_t *)mmapbuf + size, extradata, extradata_size); - } - - ret = write (fd, &func_type, sizeof(func_type)); - - CODEC_LOG(2, "leave: %s\n", __func__); - - return ret; -} - -int gst_emul_codec_device_close (GstEmulDec *emuldec) -{ - int width, height; - uint32_t bufsize; - int fd, ret = 0; - void *mmapbuf; - - CODEC_LOG(2, "enter: %s\n", __func__); - - fd = emuldec->codecbuf.fd; - if (fd < 0) { -// CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV); - GST_ERROR("failed to get %s fd.\n", CODEC_DEV); - return -1; - } - - mmapbuf = emuldec->codecbuf.buffer; - if (!mmapbuf) { -// CODEC_LOG(1, "failed to get mmaped memory address\n"); - GST_ERROR("failed to get mmaped memory address.\n"); - return -1; - } - - width = emuldec->format.video.width; - height = emuldec->format.video.height; - bufsize = ((width * height * 3) / 2) + 32; - -// CODEC_LOG(2, "release mmaped memory region of %s\n", CODEC_DEV); - GST_DEBUG("release mmaped memory region of %s.\n", CODEC_DEV); - ret = munmap (mmapbuf, bufsize); - if (ret != 0) { -// CODEC_LOG(1, "failed to release mmaped memory region of %s\n", CODEC_DEV); - GST_ERROR("failed to release memory mapped region of %s.\n", CODEC_DEV); - } - -// CODEC_LOG(2, "close %s fd\n", CODEC_DEV); - - GST_DEBUG("close %s fd.\n", CODEC_DEV); - ret = close(fd); - if (ret != 0) { -// CODEC_LOG(1, "failed to close %s\n", CODEC_DEV); - GST_ERROR("failed to close %s\n", CODEC_DEV); - } - - CODEC_LOG(2, "leave: %s\n", __func__); - - return 0; -} - -void gst_emul_codec_deinit (GstEmulDec *emuldec) -{ - int fd, ret; - int func_type = CODEC_DEINIT; - void *mmapbuf; - - CODEC_LOG(2, "enter: %s\n", __func__); - - fd = emuldec->codecbuf.fd; - mmapbuf = emuldec->codecbuf.buffer; - - if (fd < 0) { -// CODEC_LOG(1, "failed to get %s fd\n", CODEC_DEV); - GST_ERROR("failed to get %s fd.\n", CODEC_DEV); - return; - } - - if (!mmapbuf) { -// CODEC_LOG(1, "failed to get mmaped memory address\n"); - GST_ERROR("failed to get mmaped memory address.\n"); - return; - } - - ret = write (fd, &func_type, sizeof(func_type)); - - /* close device fd and release mapped memory region */ - gst_emul_codec_device_close (emuldec); - - CODEC_LOG(2, "leave: %s\n", __func__); -} - -int gst_emul_decode_video (GstEmulDec *emuldec, guint8 *in_buf, guint in_size, - GstBuffer **out_buf, GstTSInfo *dec_info) -{ - int fd, size = 0, ret; - guint out_size; - int api_index = CODEC_DECODE_VIDEO; - void *mmapbuf; - *out_buf = NULL; - - CODEC_LOG(2, "enter: %s\n", __func__); - -#if 0 - GstCaps *caps; - caps = gst_emul_codectype_to_caps (emuldec, emuldec->codecinfo); - if (!gst_pad_set_caps (emuldec->srcpad, caps)) { - GST_ERROR_OBJECT(emuldec, "failed to set caps for srcpad.\n"); -// gst_buffer_unref (buffer); -// return GST_FLOW_NOT_NEGOTIATED; - } -#endif - - fd = emuldec->codecbuf.fd; - if (fd < 0) { - GST_ERROR_OBJECT(emuldec, "failed to get %s fd\n", CODEC_DEV); - return -1; - } - - mmapbuf = emuldec->codecbuf.buffer; - if (!mmapbuf) { - GST_ERROR_OBJECT(emuldec, "failed to get mmaped memory address\n"); - return -1; - } - - memcpy ((uint8_t *)mmapbuf + size, &in_size, sizeof(guint)); - size += sizeof(guint); - memcpy ((uint8_t *)mmapbuf + size, &dec_info->timestamp, sizeof(GstClockTime)); - size += sizeof(GstClockTime); - memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size); - - /* provide raw image for decoding to qemu */ - ret = write (fd, &api_index, sizeof(api_index)); - - memcpy (&out_size, (uint8_t *)mmapbuf, sizeof(out_size)); - size = sizeof(out_size); - printf("outbuf size: %d\n", out_size); - - ret = gst_pad_alloc_buffer_and_set_caps (emuldec->srcpad, - GST_BUFFER_OFFSET_NONE, out_size, - GST_PAD_CAPS (emuldec->srcpad), out_buf); - - gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (emuldec->srcpad)); - - if (GST_BUFFER_DATA(*out_buf)) { - GST_DEBUG_OBJECT(emuldec, "copy decoded frame into out_buf.\n"); - memcpy (GST_BUFFER_DATA(*out_buf), (uint8_t *)mmapbuf + size, out_size); - } else { - GST_ERROR_OBJECT(emuldec, "failed to allocate output buffer.\n"); - } - - CODEC_LOG(2, "leave: %s\n", __func__); - - return ret; -} - -int gst_emul_decode_audio (GstEmulDec *emuldec, guint8 *in_buf, guint in_size, - GstBuffer **out_buf, GstTSInfo *dec_info) -{ - int fd, size = 0; - guint out_size = 0; - gint len = -1, have_data = 0; - int api_index = CODEC_DECODE_AUDIO; - void *mmapbuf = NULL; - - fd = emuldec->codecbuf.fd; - if (fd < 0) { - GST_ERROR_OBJECT(emuldec, "failed to get %s fd\n", CODEC_DEV); - return -1; - } - - mmapbuf = emuldec->codecbuf.buffer; - if (!mmapbuf) { - GST_ERROR_OBJECT(emuldec, "failed to get mmaped memory address\n"); - return -1; - } - - memcpy ((uint8_t *)mmapbuf + size, &in_size, sizeof(guint)); - size += sizeof(guint); - memcpy ((uint8_t *)mmapbuf + size, in_buf, in_size); - - write (fd, &api_index, sizeof(api_index)); - - memcpy (&out_size, (uint8_t *)mmapbuf + size, sizeof(out_size)); - size = sizeof(out_size); - memcpy (&len, (uint8_t *)mmapbuf + size, sizeof(len)); - size += sizeof(len); - memcpy (&have_data, (uint8_t *)mmapbuf + size, sizeof(have_data)); - size += sizeof(have_data); - - printf("decode audio, out_size: %d, len: %d, have_data: %d\n", out_size, len, have_data); - - *out_buf = gst_buffer_new(); - GST_BUFFER_DATA (*out_buf) = GST_BUFFER_MALLOCDATA (*out_buf) = g_malloc0 (out_size); - GST_BUFFER_SIZE (*out_buf) = out_size; - GST_BUFFER_FREE_FUNC (*out_buf) = g_free; - if (GST_PAD_CAPS(emuldec->srcpad)) { - gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (emuldec->srcpad)); - } - - if (GST_BUFFER_DATA(*out_buf)) { - CODEC_LOG(2, "copy decoding audio data.\n"); -// memcpy (GST_BUFFER_DATA(*out_buf), (uint8_t *)mmapbuf + size, have_data); - memcpy (GST_BUFFER_DATA(*out_buf), (uint8_t *)mmapbuf + size, out_size); - } else { - CODEC_LOG(1, "failed to allocate output buffer\n"); - } - - if (len >= 0 && have_data > 0) { - GstCaps *caps = NULL; - - caps = gst_emul_codectype_to_caps (emuldec, emuldec->codecinfo); - if (!gst_pad_set_caps (emuldec->srcpad, caps)) { - CODEC_LOG(1, "failed to set caps to srcpad.\n"); - } else { - gst_caps_unref (caps); - } - - GstClockTime out_timestamp, out_duration; - gint64 out_offset; - - GST_BUFFER_SIZE (*out_buf) = have_data; - - if (GST_CLOCK_TIME_IS_VALID (dec_info->timestamp)) { - out_timestamp = dec_info->timestamp; - } else { - // TODO - } - - emuldec->format.audio.depth = 2; - - CODEC_LOG(1, "depth: %d, channels: %d, sample_rate: %d\n", - emuldec->format.audio.depth, - emuldec->format.audio.channels, - emuldec->format.audio.samplerate); - - out_duration = gst_util_uint64_scale (have_data, GST_SECOND, - emuldec->format.audio.depth * emuldec->format.audio.channels * - emuldec->format.audio.samplerate); - out_offset = dec_info->offset; - - GST_BUFFER_TIMESTAMP (*out_buf) = out_timestamp; - GST_BUFFER_DURATION (*out_buf) = out_duration; - GST_BUFFER_OFFSET (*out_buf) = out_offset; - gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (emuldec->srcpad)); - - if (GST_CLOCK_TIME_IS_VALID (out_timestamp)) { - // TODO -// printf("out timestamp is valid.\n"); - } - - GST_LOG_OBJECT (emuldec, - "timestamp:%" GST_TIME_FORMAT ", duration:%" GST_TIME_FORMAT - ", size %u", GST_TIME_ARGS (out_timestamp), GST_TIME_ARGS (out_duration), - GST_BUFFER_SIZE (*out_buf)); - -#if 0 - { - GstClockTime stop; - gint64 diff, ctime, cstop; - - stop = out_timestamp + out_duration; - } -#endif - - } else { - CODEC_LOG(1, "failed to decode audio.\n"); - gst_buffer_unref (*out_buf); - *out_buf = NULL; - } -#if 0 - /* the next timestamp we'll use when interpolating */ - if (GST_CLOCK_TIME_IS_VALID (out_timestamp)) - emuldec->next_out = out_timestamp + out_duration; - - /* now see if we need to clip the buffer against the segment boundaries. */ - if (G_UNLIKELY (!clip_audio_buffer (emuldec, *out_buf, out_timestamp, - out_duration))) - goto clipped; - } else { - gst_buffer_unref (*out_buf); - *out_buf = NULL; - } - - /* If we don't error out after the first failed read with the AAC decoder, - * we must *not* carry on pushing data, else we'll cause segfaults... */ - if (len == -1 && (in_plugin->id == CODEC_ID_AAC - || in_plugin->id == CODEC_ID_AAC_LATM)) { - GST_ELEMENT_ERROR (emuldec, STREAM, DECODE, (NULL), - ("Decoding of AAC stream by FFMPEG failed.")); - *ret = GST_FLOW_ERROR; - } - -beach: - GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d", - *ret, *out_buf, len); - return len; - - /* ERRORS */ -clipped: - { - GST_DEBUG_OBJECT (emuldec, "buffer clipped"); - gst_buffer_unref (*out_buf); - *out_buf = NULL; - goto beach; - } -#endif - - return len; -} - -GstCaps * -gst_emul_video_caps_new (CodecInfo *info, const char *mimetype, - const char *fieldname, ...) -{ - GstStructure *structure = NULL; - GstCaps *caps = NULL; - gint i; - va_list var_args; - - if (g_str_has_prefix(info->codec_name, "h263")) { - /* 128x96, 176x144, 352x288, 704x576, and 1408x1152. slightly reordered - * because we want automatic negotiation to go as close to 320x240 as - * possible. */ - const static gint widths[] = { 352, 704, 176, 1408, 128 }; - const static gint heights[] = { 288, 576, 144, 1152, 96 }; - GstCaps *temp; - gint n_sizes = G_N_ELEMENTS (widths); - - caps = gst_caps_new_empty (); - for (i = 0; i < n_sizes; i++) { - temp = gst_caps_new_simple (mimetype, - "width", G_TYPE_INT, widths[i], - "height", G_TYPE_INT, heights[i], - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - - gst_caps_append (caps, temp); - } - } - - /* no fixed caps or special restrictions applied; - * default unfixed setting */ - if (!caps) { - GST_DEBUG ("Creating default caps"); - caps = gst_caps_new_simple (mimetype, - "width", GST_TYPE_INT_RANGE, 16, 4096, - "height", GST_TYPE_INT_RANGE, 16, 4096, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - } - - for (i = 0; i < gst_caps_get_size (caps); i++) { - va_start (var_args, fieldname); - structure = gst_caps_get_structure (caps, i); - gst_structure_set_valist (structure, fieldname, var_args); - va_end (var_args); - } - - return caps; -} - -GstCaps * -gst_emul_audio_caps_new (CodecInfo *info, const char *mimetype, - const char *fieldname, ...) -{ - GstStructure *structure = NULL; - GstCaps *caps = NULL; - gint i; - va_list var_args; - - gint maxchannels = 2; - const gint *rates = NULL; - gint n_rates = 0; - - if (strcmp(info->codec_name, "aac") == 0) { - maxchannels = 6; - } else if (g_str_has_prefix(info->codec_name, "ac3")) { - const static gint l_rates[] = { 48000, 44100, 32000 }; - maxchannels = 6; - n_rates = G_N_ELEMENTS (l_rates); - rates = l_rates; - } - - caps = gst_caps_new_simple(mimetype, - "channels", GST_TYPE_INT_RANGE, 1, maxchannels, NULL); - if (n_rates) { - GValue list = { 0, }; - GstStructure *structure; - - g_value_init(&list, GST_TYPE_LIST); - for (i = 0; i < n_rates; i++) { - GValue v = { 0, }; - - g_value_init(&v, G_TYPE_INT); - g_value_set_int(&v, rates[i]); - gst_value_list_append_value(&list, &v); - g_value_unset(&v); - } - structure = gst_caps_get_structure(caps, 0); - gst_structure_set_value(structure, "rate", &list); - g_value_unset(&list); - } else { - gst_caps_set_simple(caps, "rate", GST_TYPE_INT_RANGE, 4000, 96000, NULL); - } - - for (i = 0; i < gst_caps_get_size (caps); i++) { - va_start (var_args, fieldname); - structure = gst_caps_get_structure (caps, i); - gst_structure_set_valist (structure, fieldname, var_args); - va_end (var_args); - } - - return caps; -} - -static GstCaps * -gst_emul_smpfmt_to_caps (int8_t sample_fmt, CodecInfo *info) -{ - GstCaps *caps = NULL; - - int bpp = 0; - gboolean integer = TRUE; - gboolean signedness = FALSE; - - switch (sample_fmt) { - case SAMPLE_FMT_S16: - signedness = TRUE; - bpp = 16; - break; - case SAMPLE_FMT_S32: - signedness = TRUE; - bpp = 32; - break; - case SAMPLE_FMT_FLT: - integer = FALSE; - bpp = 32; - break; - case SAMPLE_FMT_DBL: - integer = FALSE; - bpp = 64; - break; - } - - if (bpp) { - if (integer) { - caps = gst_emul_audio_caps_new (info, "audio/x-raw-int", - "signed", G_TYPE_BOOLEAN, signedness, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, bpp, "depth", G_TYPE_INT, bpp, NULL); - } else { - caps = gst_emul_audio_caps_new (info, "audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, bpp, NULL); - } - } - - if (caps != NULL) { - GST_LOG ("caps for sample_fmt=%d: %" GST_PTR_FORMAT, sample_fmt, caps); - } else { - GST_LOG ("No caps found for sample_fmt=%d", sample_fmt); - } - - return caps; -} - -GstCaps * -gst_emul_codectype_to_audio_caps (CodecInfo *info) -{ - GstCaps *caps = NULL; - - if (info->sample_fmts[0] != 0) { - GstCaps *temp; - int i; - caps = gst_caps_new_empty (); - for (i = 0; info->sample_fmts[i] != -1; i++) { - temp = gst_emul_smpfmt_to_caps (info->sample_fmts[i], info); - if (temp != NULL) { - gst_caps_append (caps, temp); - } - } - } else { - GstCaps *temp; - int i; - - caps = gst_caps_new_empty (); - for (i = 0; i <= SAMPLE_FMT_DBL; i++) { - temp = gst_emul_smpfmt_to_caps (i, info); - if (temp != NULL) { - gst_caps_append (caps, temp); - } - } - } - - return caps; -} - -GstCaps * -gst_emul_codecname_to_caps (CodecInfo *info) -{ - GstCaps *caps = NULL; - gchar *mime_type = NULL; - - if (strcmp(info->codec_name, "mpegvideo") == 0) { - - caps = gst_emul_video_caps_new (info, "video/mpeg", - "mpegversion", G_TYPE_INT, 1, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - - } else if (strcmp(info->codec_name, "mpeg4") == 0) { - - caps = gst_emul_video_caps_new (info, "video/mpeg", - "mpegversion", G_TYPE_INT, 4, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - if (info->codec_type) { // decode - gst_caps_append (caps, gst_emul_video_caps_new (info, "video/x-divx", - "divxversion", GST_TYPE_INT_RANGE, 4, 5, NULL)); - gst_caps_append (caps, gst_emul_video_caps_new - (info, "video/x-xvid", NULL)); - gst_caps_append (caps, gst_emul_video_caps_new - (info, "video/x-3ivx", NULL)); - } else { // encode - gst_caps_append (caps, gst_emul_video_caps_new (info, "video/x-divx", - "divxversion", G_TYPE_INT, 5, NULL)); - } - - } else if (strcmp(info->codec_name, "h263") == 0) { - - if (info->codec_type) { - caps = gst_emul_video_caps_new (info, "video/x-h263", - "variant", G_TYPE_STRING, "itu", NULL); - } else { - caps = gst_emul_video_caps_new (info, "video/x-h263", - "variant", G_TYPE_STRING, "itu", - "h263version", G_TYPE_STRING, "h263", NULL); - } - - } else if (strcmp(info->codec_name, "h263p") == 0) { - - caps = gst_emul_video_caps_new (info, "video/x-h263", - "variant", G_TYPE_STRING, "itu", - "h263version", G_TYPE_STRING, "h263p", NULL); - - } else if (strcmp(info->codec_name, "h264") == 0) { - - caps = gst_emul_video_caps_new (info, "video/x-h264", NULL); - - } else if (g_str_has_prefix(info->codec_name, "msmpeg4")) { // msmpeg4v1,m msmpeg4v2, msmpeg4 - - gint version; - - if (strcmp(info->codec_name, "msmpeg4v1") == 0) { - version = 41; - } else if (strcmp(info->codec_name, "msmpeg4v2") == 0) { - version = 42; - } else { - version = 43; - } - - caps = gst_emul_video_caps_new (info, "video/x-msmpeg", - "msmpegversion", G_TYPE_INT, version, NULL); - if (info->codec_type && !strcmp(info->codec_name, "msmpeg4")) { - gst_caps_append (caps, gst_emul_video_caps_new (info, "video/x-divx", - "divxversion", G_TYPE_INT, 3, NULL)); - } - - } else if (strcmp(info->codec_name, "wmv3") == 0) { - - caps = gst_emul_video_caps_new (info, "video/x-wmv", - "wmvversion", G_TYPE_INT, 3, NULL); - - } else if (strcmp(info->codec_name, "vc1") == 0) { - - caps = gst_emul_video_caps_new (info, "video/x-wmv", - "wmvversion", G_TYPE_INT, 3, "format", GST_TYPE_FOURCC, - GST_MAKE_FOURCC ('W', 'V', 'C', '1'), NULL); -#if 0 - } else if (strcmp(info->codec_name, "vp3") == 0) { - - mime_type = g_strdup ("video/x-vp3"); - - } else if (strcmp(info->codec_name, "vp8") == 0) { - - mime_type = g_strdup ("video/x-vp8"); -#endif - } else if (strcmp(info->codec_name, "mp3") == 0) { - - mime_type = g_strdup ("audio/mpeg"); - if (info->codec_type) { - caps = gst_caps_new_simple(mime_type, "mpegversion", - G_TYPE_INT, 1, "layer", GST_TYPE_INT_RANGE, 1, 3, NULL); - } - } else if (strcmp(info->codec_name, "mp3adu") == 0) { - - mime_type = g_strdup_printf ("audio/x-gst_ff-%s", info->codec_name); - caps = gst_emul_audio_caps_new (info, mime_type, NULL); - } else if (strcmp(info->codec_name, "aac") == 0) { - - mime_type = g_strdup ("audio/mpeg"); - caps = gst_emul_audio_caps_new (info, mime_type, NULL); - if (info->codec_type) { - GValue arr = { 0, }; - GValue item = { 0, }; - - g_value_init (&arr, GST_TYPE_LIST); - g_value_init (&item, G_TYPE_INT); - g_value_set_int (&item, 2); - gst_value_list_append_value (&arr, &item); - g_value_set_int (&item, 4); - gst_value_list_append_value (&arr, &item); - g_value_unset (&item); - - gst_caps_set_value (caps, "mpegversion", &arr); - g_value_unset (&arr); - - g_value_init (&arr, GST_TYPE_LIST); - g_value_init (&item, G_TYPE_STRING); - g_value_set_string (&item, "raw"); - gst_value_list_append_value (&arr, &item); - g_value_set_string (&item, "adts"); - gst_value_list_append_value (&arr, &item); - g_value_set_string (&item, "adif"); - gst_value_list_append_value (&arr, &item); - g_value_unset (&item); - - gst_caps_set_value (caps, "stream-format", &arr); - g_value_unset (&arr); - } - - } else if (strcmp(info->codec_name, "ac3") == 0) { - - mime_type = g_strdup ("audio/x-ac3"); - caps = gst_emul_audio_caps_new (info, mime_type, NULL); - - } else if (g_str_has_prefix(info->codec_name, "wmav")) { - gint version = 1; - if (strcmp(info->codec_name, "wmav2") == 0) { - version = 2; - } - mime_type = g_strdup ("audio/x-wma"); - caps = gst_emul_audio_caps_new (info, mime_type, "wmaversion", - G_TYPE_INT, version, "block_align", GST_TYPE_INT_RANGE, 0, G_MAXINT, - "bitrate", GST_TYPE_INT_RANGE, 0, G_MAXINT, NULL); - - } else { - GST_ERROR("failed to new caps for %s.\n", info->codec_name); - } - - if (mime_type) { - g_free(mime_type); - } - - return caps; -} diff --git a/src/gstemuldev.c b/src/gstemuldev.c index 1e69249..ea8845d 100644 --- a/src/gstemuldev.c +++ b/src/gstemuldev.c @@ -1,7 +1,7 @@ /* * GStreamer codec plugin for Tizen Emulator. * - * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: * KiTae Kim @@ -22,13 +22,6 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. - */ - -/* First, include the header file for the plugin, to bring in the - * object definition and other useful things. - */ - -/* * * Contributors: * - S-Core Co., Ltd @@ -44,60 +37,62 @@ #include #include #include -#include + #include "gstemulcommon.h" -// #include "gstemuldev.h" +#include "gstemuldev.h" -#define CODEC_DEV "/dev/codec" -#define CODEC_MEM_SIZE 16 * 1024 * 1024 -int gst_emul_codec_device_open (CodecDev *info) +int +gst_emul_codec_device_open (CodecDevice *dev) { int fd; void *mmapbuf; - CODEC_LOG(2, "enter: %s\n", __func__); + printf("enter: %s\n", __func__); if ((fd = open(CODEC_DEV, O_RDWR)) < 0) { perror("Failed to open codec device."); return -1; } + GST_DEBUG("succeeded to open %s.\n", CODEC_DEV); - GST_DEBUG("succeeded to open %s.\n", CODEC_DEV); - mmapbuf = mmap (NULL, CODEC_MEM_SIZE, PROT_READ | PROT_WRITE, + mmapbuf = mmap (NULL, dev->buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (!mmapbuf) { perror("Failed to map device memory of codec."); + close(fd); return -1; } + GST_DEBUG("succeeded to map device memory.\n"); - info->fd = fd; - info->buffer = mmapbuf; + dev->fd = fd; + dev->buf = mmapbuf; return 0; } -int gst_emul_codec_device_close (CodecDev *info) +int +gst_emul_codec_device_close (CodecDevice *dev) { int fd = 0; void *mmapbuf = NULL; - CODEC_LOG(2, "enter: %s\n", __func__); + printf("enter: %s\n", __func__); - fd = info->fd; + fd = dev->fd; if (fd < 0) { GST_ERROR("Failed to get %s fd.\n", CODEC_DEV); return -1; } - mmapbuf = info->buffer; + mmapbuf = dev->buf; if (!mmapbuf) { GST_ERROR("Failed to get mmaped memory address.\n"); return -1; } GST_DEBUG("Release memory region of %s.\n", CODEC_DEV); - if (munmap(mmapbuf, CODEC_MEM_SIZE) != 0) { + if (munmap(mmapbuf, dev->buf_size) != 0) { GST_ERROR("Failed to release memory region of %s.\n", CODEC_DEV); } @@ -106,7 +101,7 @@ int gst_emul_codec_device_close (CodecDev *info) GST_ERROR("Failed to close %s. fd: %d\n", CODEC_DEV, fd); } - CODEC_LOG(2, "leave: %s\n", __func__); + printf("leave: %s\n", __func__); return 0; } diff --git a/src/gstemuldev.h b/src/gstemuldev.h index 6c01182..0bb3ccc 100644 --- a/src/gstemuldev.h +++ b/src/gstemuldev.h @@ -1,7 +1,7 @@ /* * Gstreamer codec plugin for Tizen Emulator. * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: * KiTae Kim @@ -22,18 +22,16 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. - */ - -/* First, include the header file for the plugin, to bring in the - * object definition and other useful things. - */ - -/* * * Contributors: * - S-Core Co., Ltd * */ -int gst_emul_codec_device_open (void *emuldec); -int gst_emul_codec_device_close (void *emuldec); +#ifndef __GST_EMUL_DEV_H__ +#define __GST_EMUL_DEV_H__ + +int gst_emul_codec_device_open (CodecDevice *dev); +int gst_emul_codec_device_close (CodecDevice *dev); + +#endif diff --git a/src/gstemulnewdec.c b/src/gstemulnewdec.c new file mode 100644 index 0000000..9eaf906 --- /dev/null +++ b/src/gstemulnewdec.c @@ -0,0 +1,1381 @@ +/* + * GStreamer codec plugin for Tizen Emulator. + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * KiTae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include "gstemulcommon.h" +#include "gstemulutils.h" +#include "gstemulapi.h" + +#define GST_EMULDEC_PARAMS_QDATA g_quark_from_static_string("emuldec-params") + +/* indicate dts, pts, offset in the stream */ +typedef struct +{ + gint idx; + GstClockTime timestamp; + GstClockTime duration; + gint64 offset; +} GstTSInfo; + +#define GST_TS_INFO_NONE &ts_info_none +static const GstTSInfo ts_info_none = { -1, -1, -1, -1 }; + +#define MAX_TS_MASK 0xff + +typedef struct _GstEmulDec +{ + GstElement element; + + GstPad *srcpad; + GstPad *sinkpad; + + CodecContext *context; + CodecDevice *dev; + + union { + struct { + gint width, height; + gint clip_width, clip_height; + gint par_n, par_d; + gint fps_n, fps_d; + gint old_fps_n, old_fps_d; + gboolean interlaced; + + enum PixelFormat pix_fmt; + } video; + struct { + gint channels; + gint samplerate; + gint depth; + } audio; + } format; + + gboolean discont; + gboolean clear_ts; + + /* tracking DTS/PTS */ + GstClockTime next_out; + + /* Qos stuff */ + gdouble proportion; + GstClockTime earliest_time; + gint64 processed; + gint64 dropped; + + + /* GstSegment can be used for two purposes: + * 1. performing seeks (handling seek events) + * 2. tracking playback regions (handling newsegment events) + */ + GstSegment segment; + + GstTSInfo ts_info[MAX_TS_MASK + 1]; + gint ts_idx; + + /* reverse playback queue */ + GList *queued; + +} GstEmulDec; + +typedef struct _GstEmulDecClass +{ + GstElementClass parent_class; + + CodecElement *codec; + GstPadTemplate *sinktempl; + GstPadTemplate *srctempl; +} GstEmulDecClass; + + +static GstElementClass *parent_class = NULL; + +static void gst_emuldec_base_init (GstEmulDecClass *klass); +static void gst_emuldec_class_init (GstEmulDecClass *klass); +static void gst_emuldec_init (GstEmulDec *emuldec); +static void gst_emuldec_finalize (GObject *object); + +static gboolean gst_emuldec_setcaps (GstPad *pad, GstCaps *caps); + +// sinkpad +static gboolean gst_emuldec_sink_event (GstPad *pad, GstEvent *event); +static GstFlowReturn gst_emuldec_chain (GstPad *pad, GstBuffer *buffer); + +// srcpad +static gboolean gst_emuldec_src_event (GstPad *pad, GstEvent *event); +static GstStateChangeReturn gst_emuldec_change_state (GstElement *element, + GstStateChange transition); + +static gboolean gst_emuldec_negotiate (GstEmulDec *dec, gboolean force); + +static gint gst_emuldec_frame (GstEmulDec *emuldec, guint8 *data, + guint size, gint *got_data, + const GstTSInfo *dec_info, GstFlowReturn *ret); + +static gboolean gst_emuldec_open (GstEmulDec *emuldec); +static gboolean gst_emuldec_close (GstEmulDec *emuldec); + + + +static const GstTSInfo * +gst_ts_info_store (GstEmulDec *dec, GstClockTime timestamp, + GstClockTime duration, gint64 offset) +{ + gint idx = dec->ts_idx; + dec->ts_info[idx].idx = idx; + dec->ts_info[idx].timestamp = timestamp; + dec->ts_info[idx].duration = duration; + dec->ts_info[idx].offset = offset; + dec->ts_idx = (idx + 1) & MAX_TS_MASK; + + return &dec->ts_info[idx]; +} + +static const GstTSInfo * +gst_ts_info_get (GstEmulDec *dec, gint idx) +{ + if (G_UNLIKELY (idx < 0 || idx > MAX_TS_MASK)) + return GST_TS_INFO_NONE; + + return &dec->ts_info[idx]; +} + +static void +gst_emuldec_reset_ts (GstEmulDec *emuldec) +{ + emuldec->next_out = GST_CLOCK_TIME_NONE; +} + +static void +gst_emuldec_update_qos (GstEmulDec *emuldec, gdouble proportion, + GstClockTime timestamp) +{ + GST_LOG_OBJECT (emuldec, "update QOS: %f, %" GST_TIME_FORMAT, + proportion, GST_TIME_ARGS (timestamp)); + + GST_OBJECT_LOCK (emuldec); + emuldec->proportion = proportion; + emuldec->earliest_time = timestamp; + GST_OBJECT_UNLOCK (emuldec); +} + +static void +gst_emuldec_reset_qos (GstEmulDec *emuldec) +{ + gst_emuldec_update_qos (emuldec, 0.5, GST_CLOCK_TIME_NONE); + emuldec->processed = 0; + emuldec->dropped = 0; +} + +static gboolean +gst_emuldec_do_qos (GstEmulDec *emuldec, GstClockTime timestamp, + gboolean *mode_switch) +{ + GstClockTimeDiff diff; + gdouble proportion; + GstClockTime qostime, earliest_time; + gboolean res = TRUE; + + *mode_switch = FALSE; + + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) { + emuldec->processed++; + return TRUE; + } + + proportion = emuldec->proportion; + earliest_time = emuldec->earliest_time; + + qostime = gst_segment_to_running_time (&emuldec->segment, GST_FORMAT_TIME, + timestamp); + + + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime))) { + emuldec->processed++; + return TRUE; + } + + diff = GST_CLOCK_DIFF (qostime, earliest_time); + + if (proportion < 0.4 && diff < 0 ){ + emuldec->processed++; + return TRUE; + } else { + if (diff >= 0) { +// if (emuldec->waiting_for_key) { + if (0) { + res = FALSE; + } else { + } + + GstClockTime stream_time, jitter; + GstMessage *qos_msg; + + emuldec->dropped++; + stream_time = + gst_segment_to_stream_time (&emuldec->segment, GST_FORMAT_TIME, + timestamp); + jitter = GST_CLOCK_DIFF (qostime, earliest_time); + qos_msg = + gst_message_new_qos (GST_OBJECT_CAST (emuldec), FALSE, qostime, + stream_time, timestamp, GST_CLOCK_TIME_NONE); + gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000); + gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS, + emuldec->processed, emuldec->dropped); + gst_element_post_message (GST_ELEMENT_CAST (emuldec), qos_msg); + + return res; + } + } +} + +static void +clear_queued (GstEmulDec *emuldec) +{ + g_list_foreach (emuldec->queued, (GFunc) gst_mini_object_unref, NULL); + g_list_free (emuldec->queued); + emuldec->queued = NULL; +} + +static GstFlowReturn +flush_queued (GstEmulDec *emuldec) +{ + GstFlowReturn res = GST_FLOW_OK; + + printf("flush queued\n"); + + while (emuldec->queued) { + GstBuffer *buf = GST_BUFFER_CAST (emuldec->queued->data); + + GST_LOG_OBJECT (emuldec, "pushing buffer %p, offset %" + G_GUINT64_FORMAT ", timestamp %" + GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf, + GST_BUFFER_OFFSET (buf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); + + res = gst_pad_push (emuldec->srcpad, buf); + + emuldec->queued = + g_list_delete_link (emuldec->queued, emuldec->queued); + } + + return res; +} + +static void +gst_emuldec_drain (GstEmulDec *emuldec) +{ + GstEmulDecClass *oclass; + + oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); + + // TODO: drain +#if 1 + { + gint have_data, len, try = 0; + + do { + GstFlowReturn ret; + + len = + gst_emuldec_frame (emuldec, NULL, 0, &have_data, &ts_info_none, &ret); + if (len < 0 || have_data == 0) { + printf("drain. try: %d\n", try); + + break; + } + } while (try++ < 10); + } +#endif + + if (emuldec->segment.rate < 0.0) { + flush_queued (emuldec); + } +} + +/* + * Implementation + */ +static void +gst_emuldec_base_init (GstEmulDecClass *klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstCaps *sinkcaps, *srccaps; + GstPadTemplate *sinktempl, *srctempl; + CodecElement *codec; + gchar *longname, *classification; + + codec = + (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), + GST_EMULDEC_PARAMS_QDATA); + + longname = g_strdup_printf ("%s Decoder", codec->longname); + classification = g_strdup_printf ("Codec/Decoder/%s", + (codec->media_type == AVMEDIA_TYPE_VIDEO) ? + "Video" : "Audio"); + + gst_element_class_set_details_simple (element_class, + longname, // longname + classification, // classification + "accelerated codec for Tizen Emulator", // description + "Kitae Kim "); // author + + g_free (longname); + g_free (classification); + + sinkcaps = gst_emul_codecname_to_caps (codec->name, NULL, FALSE); + if (!sinkcaps) { + sinkcaps = gst_caps_from_string ("unknown/unknown"); + } + + switch (codec->media_type) { + case AVMEDIA_TYPE_VIDEO: + srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv"); + break; + case AVMEDIA_TYPE_AUDIO: + srccaps = gst_emul_codectype_to_audio_caps (NULL, codec->name, FALSE, codec); + break; + default: + GST_LOG("unknown media type.\n"); + break; + } + + if (!srccaps) { + srccaps = gst_caps_from_string ("unknown/unknown"); + } + + sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, sinkcaps); + srctempl = gst_pad_template_new ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, srccaps); + + gst_element_class_add_pad_template (element_class, srctempl); + gst_element_class_add_pad_template (element_class, sinktempl); + + klass->codec = codec; + klass->sinktempl = sinktempl; + klass->srctempl = srctempl; +} + +static void +gst_emuldec_class_init (GstEmulDecClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + +#if 0 + gobject_class->set_property = gst_emuldec_set_property + gobject_class->get_property = gst_emuldec_get_property +#endif + + gobject_class->finalize = gst_emuldec_finalize; + gstelement_class->change_state = gst_emuldec_change_state; +} + +static void +gst_emuldec_init (GstEmulDec *emuldec) +{ + GstEmulDecClass *oclass; + + oclass = (GstEmulDecClass*) (G_OBJECT_GET_CLASS(emuldec)); + + emuldec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); + gst_pad_set_setcaps_function (emuldec->sinkpad, + GST_DEBUG_FUNCPTR(gst_emuldec_setcaps)); + gst_pad_set_event_function (emuldec->sinkpad, + GST_DEBUG_FUNCPTR(gst_emuldec_sink_event)); + gst_pad_set_chain_function (emuldec->sinkpad, + GST_DEBUG_FUNCPTR(gst_emuldec_chain)); + + emuldec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src") ; + gst_pad_use_fixed_caps (emuldec->srcpad); + gst_pad_set_event_function (emuldec->srcpad, + GST_DEBUG_FUNCPTR(gst_emuldec_src_event)); + + gst_element_add_pad (GST_ELEMENT(emuldec), emuldec->sinkpad); + gst_element_add_pad (GST_ELEMENT(emuldec), emuldec->srcpad); + + // init + emuldec->context = g_malloc0 (sizeof(CodecContext)); + if (!emuldec->context) { + printf("failed to allocate memory.\n"); + } + emuldec->dev = g_malloc0 (sizeof(CodecDevice)); + if (!emuldec->dev) { + printf("failed to allocate memory.\n"); + } + + emuldec->format.video.par_n = -1; + emuldec->format.video.fps_n = -1; + emuldec->format.video.old_fps_n = -1; + + emuldec->queued = NULL; + gst_segment_init (&emuldec->segment, GST_FORMAT_TIME); +} + +static void +gst_emuldec_finalize (GObject *object) +{ + // Deinit Decoder + GstEmulDec *emuldec = (GstEmulDec *) object; + + printf ("gst_emuldec_finalize\n"); + if (emuldec->context != NULL) { + g_free (emuldec->context); + emuldec->context = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_emuldec_src_event (GstPad *pad, GstEvent *event) +{ + GstEmulDec *emuldec; + gboolean res; + + emuldec = (GstEmulDec *) gst_pad_get_parent (pad); + + switch (GST_EVENT_TYPE (event)) { + /* Quality Of Service (QOS) event contains a report + about the current real-time performance of the stream.*/ + case GST_EVENT_QOS: + { + gdouble proportion; + GstClockTimeDiff diff; + GstClockTime timestamp; + + printf("GST_EVENT_QOS\n"); + gst_event_parse_qos (event, &proportion, &diff, ×tamp); + GST_LOG_OBJECT (emuldec, "update QOS: %f, %" GST_TIME_FORMAT, + proportion, GST_TIME_ARGS (timestamp)); + + /* update our QoS values */ + gst_emuldec_update_qos (emuldec, proportion, timestamp + diff); + + /* forward upstream */ + res = gst_pad_push_event (emuldec->sinkpad, event); + break; + } + default: + /* forward upstream */ + res = gst_pad_push_event (emuldec->sinkpad, event); + break; + } + + gst_object_unref (emuldec); + + return 0; +} + +static gboolean +gst_emuldec_sink_event (GstPad *pad, GstEvent *event) +{ + GstEmulDec *emuldec; + gboolean ret = FALSE; + + emuldec = (GstEmulDec *) gst_pad_get_parent (pad); + + GST_DEBUG_OBJECT (emuldec, "Handling %s event", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + printf("GST_EVENT_EOS\n"); + gst_emuldec_drain (emuldec); + break; + case GST_EVENT_FLUSH_STOP: + { + printf("GST_EVENT_FLUSH_STOP\n"); + + gst_emuldec_reset_ts (emuldec); +// gst_emuldec_reset_qos (emuldec); + gst_segment_init (&emuldec->segment, GST_FORMAT_TIME); + + /* clear queue */ + clear_queued (emuldec); + } + break; + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + GstFormat format; + gint64 start, stop, time; + gdouble rate, arate; + + printf ("GST_EVENT_NEWSEGMENT\n"); + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + + switch (format) { + case GST_FORMAT_TIME: + printf ("GST_FORMAT_TIME\n"); + break; + case GST_FORMAT_BYTES: + { + gint bit_rate; + bit_rate = emuldec->context->audio.bit_rate; + + printf ("GST_FORMAT_BYTES\n"); + if (!bit_rate) { + // no_bitrate + GST_WARNING_OBJECT (emuldec, "no bitrate to convert BYTES to TIME"); + gst_event_unref (event); + gst_object_unref (emuldec); + return ret; + } + + GST_DEBUG_OBJECT (emuldec, "bitrate: %d", bit_rate); + + if (start != -1) { + start = gst_util_uint64_scale_int (start, GST_SECOND, bit_rate); + } + if (stop != -1) { + stop = gst_util_uint64_scale_int (stop, GST_SECOND, bit_rate); + } + if (time != -1) { + time = gst_util_uint64_scale_int (time, GST_SECOND, bit_rate); + } + + gst_event_unref (event); + + format = GST_FORMAT_TIME; + + stop = -1; + event = gst_event_new_new_segment (update, rate, format, + start, stop, time); + break; + } + default: + // invlalid format + break; + } + +#if 1 + if (emuldec->context->codec) { + gst_emuldec_drain (emuldec); + } +#endif + + gst_segment_set_newsegment_full (&emuldec->segment, update, + rate, arate, format, start, stop, time); + break; + } + default: + break; + } + + ret = gst_pad_push_event (emuldec->srcpad, event); + + gst_object_unref (emuldec); + + return ret; +} + + + +static gboolean +gst_emuldec_setcaps (GstPad *pad, GstCaps *caps) +{ + GstEmulDec *emuldec; + GstEmulDecClass *oclass; + GstStructure *structure; + const GValue *par; + const GValue *fps; + gboolean ret = TRUE; + + GST_DEBUG_OBJECT (pad, "setcaps called."); + + emuldec = (GstEmulDec *) (gst_pad_get_parent (pad)); + oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); + + GST_OBJECT_LOCK (emuldec); + +#if 0 + if (emuldec->opened) { + GST_OBJECT_UNLOCK (emuldec); + gst_emuldec_drain (emuldec); + GST_OBJECT_LOCK (emuldec); + gst_emuldec_close (emuldec); + } +#endif + + GST_LOG_OBJECT (emuldec, "size %dx%d", emuldec->context->video.width, + emuldec->context->video.height); + + gst_emul_caps_with_codecname (oclass->codec->name, oclass->codec->media_type, + caps, emuldec->context); + + GST_LOG_OBJECT (emuldec, "size after %dx%d", emuldec->context->video.width, + emuldec->context->video.height); + + if (!emuldec->context->video.fps_d || !emuldec->context->video.fps_n) { + GST_DEBUG_OBJECT (emuldec, "forcing 25/1 framerate"); + emuldec->context->video.fps_n = 1; + emuldec->context->video.fps_d = 25; + } + + structure = gst_caps_get_structure (caps, 0); + + par = gst_structure_get_value (structure, "pixel-aspect-ratio"); + if (par) { + GST_DEBUG_OBJECT (emuldec, "sink caps have pixel-aspect-ratio of %d:%d", + gst_value_get_fraction_numerator (par), + gst_value_get_fraction_denominator (par)); +#if 0 // TODO + if (emuldec->par) { + g_free(emuldec->par); + } + emuldec->par = g_new0 (GValue, 1); + gst_value_init_and_copy (emuldec->par, par); +#endif + } + + fps = gst_structure_get_value (structure, "framerate"); + if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) { + emuldec->format.video.fps_n = gst_value_get_fraction_numerator (fps); + emuldec->format.video.fps_d = gst_value_get_fraction_denominator (fps); + GST_DEBUG_OBJECT (emuldec, "Using framerate %d/%d from incoming", + emuldec->format.video.fps_n, emuldec->format.video.fps_d); + } else { + emuldec->format.video.fps_n = -1; + GST_DEBUG_OBJECT (emuldec, "Using framerate from codec"); + } + + if (strcmp (oclass->codec->name, "aac") == 0) { + const gchar *format = gst_structure_get_string (structure, "stream-format"); +#if 0 + if (format == NULL || strcmp ("format", "raw") == 0) { + emuldec->turnoff_parser = TRUE; + } +#endif + } + + if (!gst_emuldec_open (emuldec)) { + GST_DEBUG_OBJECT (emuldec, "Failed to open"); +#if 0 + if (emuldec->par) { + g_free(emuldec->par); + emuldec->par = NULL; + } +#endif + GST_OBJECT_UNLOCK (emuldec); + gst_object_unref (emuldec); + + return FALSE; + } + + gst_structure_get_int (structure, "width", + &emuldec->format.video.clip_width); + gst_structure_get_int (structure, "height", + &emuldec->format.video.clip_height); + + GST_DEBUG_OBJECT (pad, "clipping to %dx%d", + emuldec->format.video.clip_width, emuldec->format.video.clip_height); + + GST_OBJECT_UNLOCK (emuldec); + gst_object_unref (emuldec); + + return ret; +} + +static GStaticMutex gst_avcodec_mutex = G_STATIC_MUTEX_INIT; + +int +gst_emul_avcodec_open (CodecContext *ctx, CodecElement *codec, CodecDevice *dev) +{ + int ret; + + g_static_mutex_lock (&gst_avcodec_mutex); + + if (gst_emul_codec_device_open (dev) < 0) { + printf("failed to open device.\n"); + return -1; + } + ret = emul_avcodec_init (ctx, codec, dev); + g_static_mutex_unlock (&gst_avcodec_mutex); + + return ret; +} + +int +gst_emul_avcodec_close (CodecContext *ctx, CodecDevice *dev) +{ + int ret; + + g_static_mutex_lock (&gst_avcodec_mutex); + + printf ("gst_emul_avcodec_close\n"); + ret = emul_avcodec_deinit (ctx, dev); + + gst_emul_codec_device_close (dev); + g_static_mutex_unlock (&gst_avcodec_mutex); + + return ret; +} + +static gboolean +gst_emuldec_open (GstEmulDec *emuldec) +{ + GstEmulDecClass *oclass; + int width, height, buf_size; + + oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); + + if (!emuldec->dev) { + return FALSE; + } + + switch (oclass->codec->media_type) { + case AVMEDIA_TYPE_VIDEO: + width = emuldec->context->video.width; + height = emuldec->context->video.height; + buf_size = gst_emul_avpicture_size (0, width, height); + break; + case AVMEDIA_TYPE_AUDIO: +// buf_size = FF_MAX_AUDIO_FRAME_SIZE; + buf_size = 1024 * 256; // 256K + break; + default: + buf_size = -1; + break; + } + + if (buf_size < 0) { + return FALSE; + } + + emuldec->dev->buf_size = buf_size; + + if (gst_emul_avcodec_open (emuldec->context, oclass->codec, emuldec->dev) < 0) { + gst_emuldec_close (emuldec); + GST_DEBUG_OBJECT (emuldec, "tzdec_%s: Failed to open codec", + oclass->codec->name); + } + +#if 0 + emuldec->opened = TRUE; +#endif + + GST_LOG_OBJECT (emuldec, "Opened codec %s", oclass->codec->name); + + switch (oclass->codec->media_type) { + case AVMEDIA_TYPE_VIDEO: + emuldec->format.video.width = 0; + emuldec->format.video.height = 0; + emuldec->format.video.clip_width = -1; + emuldec->format.video.clip_height = -1; + emuldec->format.video.pix_fmt = PIX_FMT_NB; + emuldec->format.video.interlaced = FALSE; + break; + case AVMEDIA_TYPE_AUDIO: + emuldec->format.audio.samplerate = 0; + emuldec->format.audio.channels = 0; + emuldec->format.audio.depth = 0; + break; + default: + break; + } + + gst_emuldec_reset_ts (emuldec); + + emuldec->proportion = 0.0; + emuldec->earliest_time = -1; + + return TRUE; +} + +static gboolean +gst_emuldec_close (GstEmulDec *emuldec) +{ + int ret; + + printf ("gst_emuldec_close\n"); + gst_emul_avcodec_close (emuldec->context, emuldec->dev); + + return TRUE; +} + + +static gboolean +gst_emuldec_negotiate (GstEmulDec *emuldec, gboolean force) +{ + GstEmulDecClass *oclass; + GstCaps *caps; + + oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); + + switch (oclass->codec->media_type) { + case AVMEDIA_TYPE_VIDEO: + if (!force && emuldec->format.video.width == emuldec->context->video.width + && emuldec->format.video.height == emuldec->context->video.height + && emuldec->format.video.fps_n == emuldec->format.video.old_fps_n + && emuldec->format.video.fps_d == emuldec->format.video.old_fps_d + && emuldec->format.video.pix_fmt == emuldec->context->video.pix_fmt + && emuldec->format.video.par_n == emuldec->context->video.par_n + && emuldec->format.video.par_d == emuldec->context->video.par_d) { + return TRUE; + } + emuldec->format.video.width = emuldec->context->video.width; + emuldec->format.video.height = emuldec->context->video.height; + emuldec->format.video.old_fps_n = emuldec->format.video.fps_n; + emuldec->format.video.old_fps_d = emuldec->format.video.fps_d; + emuldec->format.video.pix_fmt = emuldec->context->video.pix_fmt; + emuldec->format.video.par_n = emuldec->context->video.par_n; + emuldec->format.video.par_d = emuldec->context->video.par_d; + break; + case AVMEDIA_TYPE_AUDIO: + { + gint depth = gst_emul_smpfmt_depth (emuldec->context->audio.sample_fmt); + if (!force && emuldec->format.audio.samplerate == + emuldec->context->audio.sample_rate && + emuldec->format.audio.channels == emuldec->context->audio.channels && + emuldec->format.audio.depth == depth) { + return TRUE; + } + emuldec->format.audio.samplerate = emuldec->context->audio.sample_rate; + emuldec->format.audio.channels = emuldec->context->audio.channels; + emuldec->format.audio.depth = depth; + } + break; + default: + break; + } + + + + caps = + gst_emul_codectype_to_caps (oclass->codec->media_type, emuldec->context, + oclass->codec->name, FALSE); + + if (caps == NULL) { + GST_ELEMENT_ERROR (emuldec, CORE, NEGOTIATION, + ("Could not find GStreamer caps mapping for codec '%s'.", + oclass->codec->name), (NULL)); + return FALSE; + } + + switch (oclass->codec->media_type) { + case AVMEDIA_TYPE_VIDEO: + { + gint width, height; + gboolean interlaced; + + width = emuldec->format.video.clip_width; + height = emuldec->format.video.clip_height; + interlaced = emuldec->format.video.interlaced; + + if (width != -1 && height != -1) { + if (width < emuldec->context->video.width) { + gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL); + } + if (height < emuldec->context->video.height) { + gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL); + } + gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced, + NULL); + + if (emuldec->format.video.fps_n != -1) { + gst_caps_set_simple (caps, "framerate", + GST_TYPE_FRACTION, emuldec->format.video.fps_n, + emuldec->format.video.fps_d, NULL); + } +#if 0 + gst_emuldec_add_pixel_aspect_ratio (emuldec, + gst_caps_get_structure (caps, 0)); +#endif + } + } + break; + case AVMEDIA_TYPE_AUDIO: + default: + break; + } + + if (!gst_pad_set_caps (emuldec->srcpad, caps)) { + GST_ELEMENT_ERROR (emuldec, CORE, NEGOTIATION, (NULL), + ("Could not set caps for decoder (%s), not fixed?", + oclass->codec->name)); + gst_caps_unref (caps); + return FALSE; + } + + gst_caps_unref (caps); + + return TRUE; +} + +GstBuffer * +new_aligned_buffer (gint size, GstCaps *caps) +{ + GstBuffer *buf; + + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = g_malloc0 (size); + GST_BUFFER_SIZE (buf) = size; + GST_BUFFER_FREE_FUNC (buf) = g_free; + if (caps) { + gst_buffer_set_caps (buf, caps); + } + + return buf; +} + +static gboolean +clip_audio_buffer (GstEmulDec *dec, GstBuffer *buf, + GstClockTime in_ts, GstClockTime in_dur) +{ + GstClockTime stop; + gint64 diff, cstart, cstop; + gboolean res = TRUE; + + if (G_UNLIKELY (dec->segment.format != GST_FORMAT_TIME)) { + GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : "")); + return res; + } + + // in_ts: in_timestamp. check a start time. + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) { + GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : "")); + return res; + } + + stop = + GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE; + + res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME, in_ts, + stop, &cstart, &cstop); + if (G_UNLIKELY (!res)) { + GST_LOG_OBJECT (dec, "out of segment"); + GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : "")); + return res; + } + + if (G_UNLIKELY ((diff = cstart - in_ts) > 0)) { + diff = + gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, + GST_SECOND * (dec->format.audio.depth * dec->format.audio.channels)); + + GST_DEBUG_OBJECT (dec, "clipping start to %" GST_TIME_FORMAT " %" + G_GINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff); + + GST_BUFFER_SIZE (buf) -= diff; + GST_BUFFER_DATA (buf) += diff; + } + + if (G_UNLIKELY ((diff = stop - cstop) > 0)) { + diff = + gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, + GST_SECOND * (dec->format.audio.depth * dec->format.audio.channels)); + + GST_DEBUG_OBJECT (dec, "clipping stop to %" GST_TIME_FORMAT " %" + G_GINT64_FORMAT " bytes", GST_TIME_ARGS (cstop), diff); + + GST_BUFFER_SIZE (buf) -= diff; + } + + GST_BUFFER_TIMESTAMP (buf) = cstart; + GST_BUFFER_DURATION (buf) = cstop - cstart; + + GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : "")); + return res; +} + +static gint +gst_emuldec_video_frame (GstEmulDec *emuldec, guint8 *data, guint size, + const GstTSInfo *dec_info, GstBuffer **outbuf, + GstFlowReturn *ret) +{ + gint len = -1; + GstClockTime out_timestamp, out_duration; + gint64 out_offset; + +#if 0 + len = + emul_avcodec_decode_video (emuldec->context, data, size, + (int16_t *) GST_BUFFER_DATA (*outbuf), &have_data, emuldec->dev); +#endif + + return len; +} + +static gint +gst_emuldec_audio_frame (GstEmulDec *emuldec, CodecElement *codec, + guint8 *data, guint size, + const GstTSInfo *dec_info, GstBuffer **outbuf, + GstFlowReturn *ret) +{ + gint len = -1; + gint have_data = FF_MAX_AUDIO_FRAME_SIZE; + GstClockTime out_timestamp, out_duration; + gint64 out_offset; + + *outbuf = + new_aligned_buffer (FF_MAX_AUDIO_FRAME_SIZE, + GST_PAD_CAPS (emuldec->srcpad)); + + len = emul_avcodec_decode_audio (emuldec->context, + (int16_t *) GST_BUFFER_DATA (*outbuf), &have_data, + data, size, emuldec->dev); + + GST_DEBUG_OBJECT (emuldec, + "Decode audio: len=%d, have_data=%d", len, have_data); + + if (len >= 0 && have_data > 0) { + GST_DEBUG_OBJECT (emuldec, "Creating output buffer"); + if (!gst_emuldec_negotiate (emuldec, FALSE)) { + gst_buffer_unref (*outbuf); + *outbuf = NULL; + len = -1; + GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d", + *ret, *outbuf, len); + return len; + } + + GST_BUFFER_SIZE (*outbuf) = have_data; + + if (GST_CLOCK_TIME_IS_VALID (dec_info->timestamp)) { + out_timestamp = dec_info->timestamp; + } else { + out_timestamp = emuldec->next_out; + } + + out_duration = gst_util_uint64_scale (have_data, GST_SECOND, + emuldec->format.audio.depth * emuldec->format.audio.channels * + emuldec->format.audio.samplerate); + + out_offset = dec_info->offset; + + GST_DEBUG_OBJECT (emuldec, + "Buffer created. Size: %d, timestamp: %" GST_TIME_FORMAT + ", duration: %" GST_TIME_FORMAT, have_data, + GST_TIME_ARGS (out_timestamp), GST_TIME_ARGS (out_duration)); + + GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp; + GST_BUFFER_DURATION (*outbuf) = out_duration; + GST_BUFFER_OFFSET (*outbuf) = out_offset; + gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (emuldec->srcpad)); + + if (GST_CLOCK_TIME_IS_VALID (out_timestamp)) { + emuldec->next_out = out_timestamp + out_duration; + } + + if (G_UNLIKELY (!clip_audio_buffer (emuldec, *outbuf, + out_timestamp, out_duration))) { + GST_DEBUG_OBJECT (emuldec, "buffer_clipped"); + gst_buffer_unref (*outbuf); + *outbuf = NULL; + GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d", *ret, *outbuf, len); + return len; + } + } else { + gst_buffer_unref (*outbuf); + *outbuf = NULL; + } + + if (len == -1 && !strcmp(codec->name, "aac")) { + GST_ELEMENT_ERROR (emuldec, STREAM, DECODE, (NULL), + ("Decoding of AAC stream by gst-emul-codec failed.")); + *ret = GST_FLOW_ERROR; + } + + GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d", + *ret, *outbuf, len); + return len; +} + +static gint +gst_emuldec_frame (GstEmulDec *emuldec, guint8 *data, guint size, + gint *got_data, const GstTSInfo *dec_info, GstFlowReturn *ret) +{ + GstEmulDecClass *oclass; + GstBuffer *outbuf = NULL; + gint have_data = 0, len = 0; + + if (G_UNLIKELY (emuldec->context->codec == NULL)) { + // no_codec + GST_ERROR_OBJECT (emuldec, "no codec context"); + return -1; + } + + *ret = GST_FLOW_OK; + + oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); + + switch (oclass->codec->media_type) { + case AVMEDIA_TYPE_VIDEO: + len = gst_emuldec_video_frame (emuldec, data, size, + dec_info, &outbuf, ret); + break; + case AVMEDIA_TYPE_AUDIO: + len = gst_emuldec_audio_frame (emuldec, oclass->codec, data, size, + dec_info, &outbuf, ret); + if (outbuf == NULL && emuldec->discont) { + GST_DEBUG_OBJECT (emuldec, "no buffer but keeping timestamp"); +// emuldec->clear_ts = FALSE; + } + break; + default: + GST_ERROR_OBJECT (emuldec, "Asked to decode non-audio/video frame!"); + g_assert_not_reached (); + break; + } + + if (outbuf) { + have_data = 1; + } + + if (len < 0 || have_data < 0) { + GST_WARNING_OBJECT (emuldec, + "tzdec_%s: decoding error (len: %d, have_data: %d)", + oclass->codec->name, len, have_data); + *got_data = 0; + return len; + } else if (len == 0 && have_data == 0) { + *got_data = 0; + return len; + } else { + *got_data = 1; + } + + if (outbuf) { + GST_LOG_OBJECT (emuldec, + "Decoded data, now pushing buffer %p with offset %" G_GINT64_FORMAT + ", timestamp %" GST_TIME_FORMAT " and duration %" GST_TIME_FORMAT, + outbuf, GST_BUFFER_OFFSET (outbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf))); + + if (emuldec->discont) { + /* GST_BUFFER_FLAG_DISCONT : + * the buffer marks a data discontinuity in the stream. This typically + * occurs after a seek or a dropped buffer from a live or network source. + */ + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); + emuldec->discont = FALSE; + } + + if (emuldec->segment.rate > 0.0) { + // push forward + *ret = gst_pad_push (emuldec->srcpad, outbuf); + } else { + // push reverse + printf("push reverse.\n"); + emuldec->queued = g_list_prepend (emuldec->queued, outbuf); + *ret = GST_FLOW_OK; + } + } else { + GST_DEBUG_OBJECT (emuldec, "Didn't get a decoded buffer"); + } + + return len; +} + +static GstFlowReturn +gst_emuldec_chain (GstPad *pad, GstBuffer *buffer) +{ + GstEmulDec *emuldec; + GstEmulDecClass *oclass; + guint8 *in_buf; + guint in_size, len, have_data; + GstFlowReturn ret = GST_FLOW_OK; + GstClockTime in_timestamp; + GstClockTime in_duration; + gboolean discont; + gint64 in_offset; + const GstTSInfo *in_info; + const GstTSInfo *dec_info; + + emuldec = (GstEmulDec *) (GST_PAD_PARENT (pad)); + +#if 0 + if (G_UNLIKELY (!emuldec->opened)) { + // not_negotiated + oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); + GST_ELEMENT_ERROR (emuldec, CORE, NEGOTIATION, (NULL), + ("tzdec_%s: input format was not set before data start", + oclass->codec->name)); + gst_buffer_unref (buffer); + return GST_FLOW_NOT_NEGOTIATED; + } +#endif + + discont = GST_BUFFER_IS_DISCONT (buffer); + +// FIXME + if (G_UNLIKELY (discont)) { + GST_DEBUG_OBJECT (emuldec, "received DISCONT"); + printf("discont 1\n"); + gst_emuldec_drain (emuldec); + printf("discont 2\n"); +// gst_emuldec_flush_pcache (emuldec); + // flush buffers + emuldec->discont = TRUE; + gst_emuldec_reset_ts (emuldec); + } +// emuldec->clear_ts = TRUE; + + oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec)); +#if 0 + if (G_UNLIKELY (emuldec->waiting_for_key)) { + if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT) && + oclass->codec->media_type != AVMEDIA_TYPE_AUDIO) { + // skip_keyframe + } + emuldec->waiting_for_key = FALSE; + } + + if (emuldec->pcache) { + GST_LOG_OBJECT (emuldec, "join parse cache"); + buffer = gst_buffer_join (emuldec->pcache, buffer); + emuldec->pcache = NULL; + } +#endif + + in_timestamp = GST_BUFFER_TIMESTAMP (buffer); + in_duration = GST_BUFFER_DURATION (buffer); + in_offset = GST_BUFFER_OFFSET (buffer); + + in_info = gst_ts_info_store (emuldec, in_timestamp, in_duration, in_offset); + +#if 0 + if (in_timestamp != -1) { + if (!emuldec->reordered_in && emuldec->last_in != -1) { + if (in_timestamp < emuldec->last_in) { + GST_LOG_OBJECT (emuldec, "detected reordered input timestamps"); + emuldec->reordered_in = TRUE; + emuldec->last_diff = GST_CLOCK_TIME_NONE; + } else if (in_timestamp > emuldec->last_in) { + GstClockTime diff; + diff = in_timestamp - emuldec->last_in; + if (emuldec->last_frames) { + diff /= emuldec->last_frames; + } + + GST_LOG_OBJECT (emuldec, "estimated duration %" GST_TIME_FORMAT " %u", + GST_TIME_ARGS (diff), emuldec->last_frames); + + emuldec->last_diff = diff; + } + } + emuldec->last_in = in_timestamp; + emuldec->last_frames; + } +#endif + + in_buf = GST_BUFFER_DATA (buffer); + in_size = GST_BUFFER_SIZE (buffer); + + dec_info = in_info; + + len = + gst_emuldec_frame (emuldec, in_buf, in_size, &have_data, dec_info, &ret); + + gst_buffer_unref (buffer); + + return ret; +} + +static GstStateChangeReturn +gst_emuldec_change_state (GstElement *element, GstStateChange transition) +{ + GstEmulDec *emuldec = (GstEmulDec *) element; + GstStateChangeReturn ret; + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_OBJECT_LOCK (emuldec); + gst_emuldec_close (emuldec); + GST_OBJECT_UNLOCK (emuldec); + + /* clear queue */ + clear_queued (emuldec); + break; + default: + break; + } + + return ret; +} + +gboolean +gst_emuldec_register (GstPlugin *plugin, GList *element) +{ + GTypeInfo typeinfo = { + sizeof (GstEmulDecClass), + (GBaseInitFunc) gst_emuldec_base_init, + NULL, + (GClassInitFunc) gst_emuldec_class_init, + NULL, + NULL, + sizeof (GstEmulDec), + 0, + (GInstanceInitFunc) gst_emuldec_init, + }; + + GType type; + gchar *type_name; + gint rank = GST_RANK_PRIMARY; + gboolean ret = TRUE; + GList *elem = element; + CodecElement *codec = NULL; + + /* register element */ + while ((elem = g_list_next (elem))) { + codec = (CodecElement *)elem->data; + if (!codec) { + ret = FALSE; + break; + } + + if (codec->codec_type != CODEC_TYPE_DECODE) { + continue; + } + + type_name = g_strdup_printf ("tzdec_%s", codec->name); + type = g_type_from_name (type_name); + if (!type) { + type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0); + g_type_set_qdata (type, GST_EMULDEC_PARAMS_QDATA, (gpointer) codec); + } + + if (!gst_element_register (plugin, type_name, rank, type)) { + g_free (type_name); + return FALSE; + } + g_free (type_name); + } + + return ret; +} + diff --git a/src/gstemulnewenc.c b/src/gstemulnewenc.c new file mode 100644 index 0000000..b6e713a --- /dev/null +++ b/src/gstemulnewenc.c @@ -0,0 +1,617 @@ +/* + * GStreamer codec plugin for Tizen Emulator. + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * KiTae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "gstemulcommon.h" + +#define GST_EMULENC_PARAMS_QDATA g_quark_from_static_string("emulenc-params"); + +typedef struct _GstEmulEnc +{ + GstElement element; + + GstPad *srcpad; + GstPad *sinkpad; + + union { + struct { + gint width; + gint height; + gint framerate_num; + gint framerate_den; + gint pix_fmt; + } video; + struct { + gint channels; + gint samplerate; + gint depth; + } audio; + } format; + + GstAdapter *adapter; + + // TODO: needs a certain container such as AVCodecContext. + guint extradata_size; + guint8 *extradata; + + CodecDev codecbuf; +} GstEmulEnc; + +typedef struct _GstEmulEncClass +{ + GstElementClass parent_class; + + CodecInfo *codecinfo; + GstPadTemplate *sinktempl, *srctempl; + GstCaps *sinkcaps; +} GstEmulEncClass; + +static GstElementClass *parent_class = NULL; + +static void gst_emulenc_base_init (GstEmulEncClass *klass); +static void gst_emulenc_class_init (GstEmulEncClass *klass); +static void gst_emulenc_init (GstEmulEnc *emulenc); +static void gst_emulenc_finalize (GObject *object); + +static gboolean gst_emulenc_setcaps (GstPad *pad, GstCaps *caps); +static gboolean gst_emulenc_getcaps (GstPad *pad); + +static GstFlowReturn gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer); +static GstFlowReturn gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer); + +static gboolean gst_emulenc_event_video (GstPad *pad, GstEvent *event); +static gboolean gst_emulenc_event_src (GstPad *pad, GstEvent *event); + +static GstStateChangeReturn gst_emulenc_change_state (GstElement *element, GstStateChange transition); + +int gst_emul_codec_init (GstEmulEnc *emulenc); +void gst_emul_codec_deinit (GstEmulEnc *emulenc); + +#if 0 +int gst_emul_codec_encode_video (GstEmulEnc *emulenc, guint8 *in_buf, guint in_size, + GstBuffer **out_buf, GstClockTime in_timestamp); +int gst_emul_codec_encode_audio (GstEmulEnc *emulenc, guint8 *in_buf, guint in_size, + GstBuffer **out_buf, GstClockTime in_timestamp); +#endif + +/* + * Implementation + */ +static void +gst_emulenc_base_init (GstEmulEncClass *klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstPadTemplate *sinktempl = NULL, *srctempl = NULL; + GstCaps *sinkcaps = NULL, *srccaps = NULL; + CodecInfo *info; + gchar *longname, *classification; + + info = + (CodecInfo *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), + GST_EMULENC_PARAMS_QDATA); + + longname = g_strdup_printf ("%s Encoder", info->codec_longname); + + classification = g_strdup_printf ("Codec/Encoder/%s", + (info->media_type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio"); + + gst_element_class_set_details_simple (element_class, + longname, + classification, + "accelerated codec for Tizen Emulator", + "Kitae Kim "); + g_free (longname); + g_free (classification); + + + if (!(srccaps = gst_emul_codecname_to_caps (info, TRUE))) { + GST_DEBUG ("Couldn't get source caps for encoder '%s'", info->codec_name); + srccaps = gst_caps_new_simple ("unknown/unknown", NULL); + } + + switch (info->media_type) { + case AVMEDIA_TYPE_VIDEO: + sinkcaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray"); + break; + case AVMEDIA_TYPE_AUDIO: + srccaps = gst_emul_codectype_to_audio_caps (info, TRUE); + break; + default: + GST_LOG("unknown media type.\n"); + break; + } + + if (!sinkcaps) { + GST_DEBUG ("Couldn't get sink caps for encoder '%s'", info->codec_name); + sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL); + } + + sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, sinkcaps); + srctempl = gst_pad_template_new ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, srccaps); + + gst_element_class_add_pad_template (element_class, srctempl); + gst_element_class_add_pad_template (element_class, sinktempl); + + klass->sinktempl = sinktempl; + klass->srctempl = srctempl; + klass->sinkcaps = NULL; +} + + static void +gst_emulenc_class_init (GstEmulEncClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + +#if 0 + gobject_class->set_property = gst_emulenc_set_property + gobject_class->get_property = gst_emulenc_get_property +#endif + + gobject_class->finalize = gst_emulenc_finalize; + + gstelement_class->change_state = gst_emulenc_change_state; +} + + static void +gst_emulenc_init (GstEmulEnc *emulenc) +{ + GstEmulEncClass *oclass; + oclass = (GstEmulEncClass*) (G_OBJECT_GET_CLASS(emulenc)); + + emulenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); + gst_pad_set_setcaps_function (emulenc->sinkpad, + GST_DEBUG_FUNCPTR(gst_emulenc_setcaps)); + gst_pad_set_getcaps_function (emulenc->sinkpad, + GST_DEBUG_FUNCPTR(gst_emulenc_getcaps)); + + emulenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); + gst_pad_use_fixed_caps (emulenc->srcpad); + + switch (oclass->codecinfo->media_type) { + case AVMEDIA_TYPE_VIDEO: + gst_pad_set_chain_function (emulenc->sinkpad, gst_emulenc_chain_video); + gst_pad_set_event_function (emulenc->sinkpad, gst_emulenc_event_video); + gst_pad_set_event_function (emulenc->srckpad, gst_emulenc_event_src); + + break; + case AVMEDIA_TYPE_AUDIO: + gst_pad_set_chain_function (emuldec->sinkpad, gst_emulenc_chain_audio); + break; + default: + break; + } + + gst_element_add_pad (GST_ELEMENT (emulenc), emuldenc->sinkpad); + gst_element_add_pad (GST_ELEMENT (emulenc), emuldenc->srcpad); + + // need to know what adapter does. + emulenc->adapter = gst_adapter_new (); +} + + static void +gst_emulenc_finalize (GObject *object) +{ + // Deinit Decoder + GstEmulEnc *emulenc = (GstEmulEnc *) object; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + static gboolean +gst_emulenc_src_event (GstPad *pad, GstEvent *event) +{ + return 0; +} + + static void +gst_emulenc_get_caps (GstEmulEnc *emulenc, GstCaps *caps) +{ + GstStructure *structure; + + int width, height, bits_per_coded_sample; + const GValue *fps; + // const GValue *par; + // guint extradata_size; + // guint8 *extradata; + + /* FFmpeg Specific Values */ + const GstBuffer *buf; + const GValue *value; + + structure = gst_caps_get_structure (caps, 0); + + value = gst_structure_get_value (structure, "codec_data"); + if (value) { + buf = GST_BUFFER_CAST (gst_value_get_mini_object (value)); + emulenc->extradata_size = GST_BUFFER_SIZE (buf); + emulenc->extradata = GST_BUFFER_DATA (buf); + } else { + CODEC_LOG (2, "no codec data\n"); + emulenc->extradata_size = 0; + emulenc->extradata = NULL; + } + +#if 1 /* video type */ + /* Common Properites, width, height and etc. */ + gst_structure_get_int (structure, "width", &width); + gst_structure_get_int (structure, "height", &height); + gst_structure_get_int (structure, "bpp", &bits_per_coded_sample); + + emulenc->format.video.width = width; + emulenc->format.video.height = height; + + fps = gst_structure_get_value (structure, "framerate"); + if (fps) { + emulenc->format.video.framerate_den = gst_value_get_fraction_numerator (fps); + emulenc->format.video.framerate_num = gst_value_get_fraction_denominator (fps); + } + +#if 0 + par = gst_structure_get_value (structure, "pixel-aspect-ratio"); + if (par) { + sample_aspect_ratio.num = gst_structure_get_fraction_numerator (par); + sample_aspect_ratio.den = gst_structure_get_fraction_denominator (par); + } +#endif +#endif + +#if 0 /* audio type */ + gst_structure_get_int (structure, "channels", &channels); + gst_structure_get_int (structure, "rate", &sample_rate); + gst_structure_get_int (structure, "block_align", &block_align); + gst_structure_get_int (structure, "bitrate", &bit_rate); + + emulenc->format.audio.channels = channels; + emulenc->format.audio.samplerate = sample_rate; +#endif + +} + + static gboolean +gst_emulenc_setcaps (GstPad *pad, GstCaps *caps) +{ + GstEmulEnc *emulenc; + GstEmulEncClass *oclass; + gboolean ret = TRUE; + + emulenc = (GstEmulEnc *) (gst_pad_get_parent (pad)); + oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc)); + + if (emulenc->opend) { + gst_emul_deinit (); + emulenc->opened = FALSE; + + gst_pad_set_caps (emulenc->srcpad, NULL); + } + + gst_emul_caps_with_codectype (codec_type, caps); + + if (!time_base.den) { + time_base.den = 25; + time_base.num = 1; + } else if (strcmp( ,"mpeg4") == 0) { + } + + // open codec + + if (gst_emul_codec_dev_open (emulenc) < 0) { + CODEC_LOG(1, "failed to access %s or mmap operation\n", CODEC_DEV); + gst_object_unref (emulenc); + return FALSE; + } + + if (gst_emul_codec_init (emulenc) < 0) { + CODEC_LOG(1, "cannot initialize codec\n"); + gst_object_unref (emulenc); + return FALSE; + } + + allowed_caps = gst_pad_get_allowed_caps (emulenc->srcpad); + if (!allowed_caps) { + allowed_caps = + gst_caps_copy (gst_pad_get_pad_template_caps (emulenc->srcpad)); + } + + gst_emul_caps_with_codecid (codec_id, codec_type, allowed_caps); + + other_caps = gst_emul_codecname_to_caps (codec_id, TRUE); + + if (!other_caps) { + // deinit + return FALSE; + } + + icaps = gst_caps_intersect (allowed_caps, other_caps); + gst_caps_unref (allowed_caps); + gst_caps_unref (other_caps); + if (gst_caps_is_empty (icaps)) { + gst_caps_unref (icaps); + return FALSE; + } + + if (gst_caps_get_size (icaps) > 1) { + GstCaps *newcaps; + + newcaps = + gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps, + 0)), NULL); + + if (!gst_pad_set_caps (emulenc->srcpad, icaps)) { + // deinit + gst_caps_unref (icaps); + return FALSE; + } + gst_object_unref (emulenc); + + // emulenc->opened = TRUE; + + return TRUE; +} + +static gboolean +gst_emulenc_event_video (GstPad *pad, GstEvent *event) +{ + GstEmulEnc *emulenc; + emulenc = (GstEmulEnc *) gst_pad_get_parent (pad); + + switch (GST_TYPE_EVENT (event)) { + case GST_EVENT_EOS: + CODEC_LOG(2, "received GST_EVENT_EOS\n"); + // flush_buffers + break; + case GST_EVENT_CUSTOM_DOWNSTREAM: + CODEC_LOG(2, "received GST_EVENT_CUSTOM_DOWNSTREAM\n"); + break; + } + + return gst_pad_push_event (emulenc->srcpad, event); +} + +static gboolean +gst_emulenc_event_src (GstPad *pad, GstEvent *event) +{ + switch (GST_EVENT_TYPE (event)) { + default: + break + } + + return TRUE; +} + +// minimum encoding buffer size. +// Used to avoid some checks during header writing. +#define FF_MIN_BUFFER_SIZE 16384 + +static inst +gst_emul_encode_video (uint8_t *outbuf, int buf_size, + uint8_t *pict_buf, uint32_t pict_buf_size) +{ + GstEmulEnc *emulenc = (GetEmulEnc *) (GST_PAD_PARENT (pad)); + int size = 0, api_index = CODEC_ENCODE_VIDEO; + int ret; + + ret = write (); + + return ret; +} + +static GstFlowReturn +gst_emulenc_encode_audio (GstEmulEnc *emulenc, guint8 *audio_in, + guint in_size, guint max_size, GstClockTime timestamp, + GstClockTime duration, gboolean discont) +{ + GstBuffer *outbuf; + guint8_t *audio_out; + gint res; + GstFlowReturn ret; + int size = 0, api_index = CODEC_ENCODE_AUDIO; + + outbuf = gst_buffer_new_alloc (max_size + FF_MIN_BUFFER_SIZE); + audio_out = GST_BUFFER_DATA (outbuf); + + // copy params to qemu + + res = write(); + + // copy output and out params from qemu + + if (res < 0) { + GST_ERROR_OBJECT (emulenc, "Failed to encode buffer: %d", res); + gst_buffer_unref (outbuf); + return GST_FLOW_OK; + } + + GST_BUFFER_SIZE (outbuf) = res; + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + GST_BUFFER_DURATION (outbuf) = duration + + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad)); + + ret = gst_pad_push (emulenc->srcpad, outbuf); + + return ret; +} + +#if 0 +static void +emulenc_setup_working_buf (GstEmulEnc * emulenc) +{ + guint wanted_size = + ffmpegenc->context->width * ffmpegenc->context->height * 6 + + FF_MIN_BUFFER_SIZE; + + /* Above is the buffer size used by ffmpeg/ffmpeg.c */ + if (ffmpegenc->working_buf == NULL || + ffmpegenc->working_buf_size != wanted_size) { + if (ffmpegenc->working_buf) + g_free (ffmpegenc->working_buf); + ffmpegenc->working_buf_size = wanted_size; + ffmpegenc->working_buf = g_malloc (ffmpegenc->working_buf_size); + } + ffmpegenc->buffer_size = wanted_size; +} +#endif + +static GstFlowReturn +gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer) +{ + GstEmulEnc *emulenc = (GetEmulEnc *) (GST_PAD_PARENT (pad)); + GstBuffer *outbuf; + gint in_size = 0; + + // setup_working_buf + // width * height * 6 + FF_MIN_BUFFER_SIZE + // + +// gst_emul_encode_video (); + + outbuf = gst_buffer_new_and_alloc (ret_size); + memcpy (GST_BUFFER_DATA(outbuf), , ret_size); + GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer); + GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (outbuf); + + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad)); + + gst_buffer_unref (buffer); + + return gst_pad_push (emulenc->srcpad, outbuf); +} + +static GstFlowReturn +gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer) +{ + GstEmulEnc *emulenc; + GstEmulEncClass *oclass; + GstClockTime timestamp, duration; + guint size; + GstFlowReturn ret; + gboolean discont; + + emulenc = (GstEmulEnc *) (GST_OBJECT_PARENT (pad)); + oclass = (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc); + + size = GST_BUFFER_SIZE (buffer); + timestamp = GST_BUFFER_TIMESTAMP (buffer); + duration = GST_BUFFER_DURATION (buffer); + discont = GST_BUFFER_IS_DISCONT (buffer); + + if (discont) { + gst_adapter_clear (emulenc->adapter); + } + +// gst_adapter_push (emulenc->adapter, buffer); + +// TODO +// gst_emul_encode_audio + + return GST_FLOW_OK; +} + +static GstStateChangeReturn +gst_emulenc_change_state (GstElement *element, GstStateChange transition) +{ + GstEmulEnc *emulenc = (GstEmulEnc*)element; + GstStateChangeReturn ret; + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + // flush buffer + gst_emul_codec_deinit (emulenc); + default: + break; + } + + return ret; +} + +gboolean +gst_emulenc_register (GstPlugin *plugin, GList *element) +{ + GTypeInfo typeinfo = { + sizeof (GstEmulEncClass), + (GBaseInitFunc) gst_emulenc_base_init, + NULL, + (GClassInitFunc) gst_emulenc_class_init, + NULL, + NULL, + sizeof (GstEmulEnc), + 0, + (GInstanceInitFunc) gst_emulenc_init, + }; + + GType type; + gchar *type_name; + gint rank = GST_RANK_PRIMARY; + gboolean ret = TRUE; + GList *elem = NULL; + CodecElement *codec = NULL; + + /* register element */ + while ((elem = g_list_next (element))) { + codec = (CodecElement *)elem->data; + if (!codec) { + ret = FALSE; + break; + } + + if (codec->codec_type != CODEC_TYPE_ENCODE) { + continue; + } + + type_name = g_strdup_printf ("tzenc_%s", codec->name); + type = g_type_from_name (type_name); + if (!type) { + type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0); + g_type_set_qdata (type, GST_EMULDEC_PARAMS_QDATA, (gpointer) codec); + } + + if (!gst_element_register (plugin, type_name, rank, type)) { + g_free (type_name); + return FALSE; + } + g_free (type_name); + } + + return ret; +} diff --git a/src/gstemulutils.c b/src/gstemulutils.c new file mode 100644 index 0000000..cff4e33 --- /dev/null +++ b/src/gstemulutils.c @@ -0,0 +1,1139 @@ +/* + * GStreamer codec plugin for Tizen Emulator. + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * KiTae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include "gstemulutils.h" +#include +#include + +gint +gst_emul_smpfmt_depth (int smp_fmt) +{ + gint depth = -1; + + switch (smp_fmt) { + case SAMPLE_FMT_U8: + depth = 1; + break; + case SAMPLE_FMT_S16: + depth = 2; + break; + case SAMPLE_FMT_S32: + case SAMPLE_FMT_FLT: + depth = 4; + break; + case SAMPLE_FMT_DBL: + depth = 8; + break; + default: + GST_ERROR ("Unhandled sample format !"); + break; + } + + return depth; +} + +// FFmpeg +static const struct +{ + guint64 ff; + GstAudioChannelPosition gst; +} _ff_to_gst_layout[] = { + { + CH_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, { + CH_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { + CH_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, { + CH_LOW_FREQUENCY, GST_AUDIO_CHANNEL_POSITION_LFE}, { + CH_BACK_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, { + CH_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { + CH_FRONT_LEFT_OF_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, { + CH_FRONT_RIGHT_OF_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, { + CH_BACK_CENTER, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, { + CH_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, { + CH_SIDE_RIGHT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, { + CH_TOP_CENTER, GST_AUDIO_CHANNEL_POSITION_NONE}, { + CH_TOP_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_NONE}, { + CH_TOP_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_NONE}, { + CH_TOP_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_NONE}, { + CH_TOP_BACK_LEFT, GST_AUDIO_CHANNEL_POSITION_NONE}, { + CH_TOP_BACK_CENTER, GST_AUDIO_CHANNEL_POSITION_NONE}, { + CH_TOP_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_NONE}, { + CH_STEREO_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, { + CH_STEREO_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT} +}; + +static GstAudioChannelPosition * +gst_ff_channel_layout_to_gst (guint64 channel_layout, guint channels) +{ + guint nchannels = 0, i, j; + GstAudioChannelPosition *pos = NULL; + gboolean none_layout = FALSE; + + for (i = 0; i < 64; i++) { + if ((channel_layout & (G_GUINT64_CONSTANT (1) << i)) != 0) { + nchannels++; + } + } + + if (channel_layout == 0) { + nchannels = channels; + none_layout = TRUE; + } + + if (nchannels != channels) { + GST_ERROR ("Number of channels is different (%u != %u)", channels, + nchannels); + return NULL; + } + + pos = g_new (GstAudioChannelPosition, nchannels); + + for (i = 0, j = 0; i < G_N_ELEMENTS (_ff_to_gst_layout); i++) { + if ((channel_layout & _ff_to_gst_layout[i].ff) != 0) { + pos[j++] = _ff_to_gst_layout[i].gst; + + if (_ff_to_gst_layout[i].gst == GST_AUDIO_CHANNEL_POSITION_NONE) { + none_layout = TRUE; + } + } + } + + if (j != nchannels) { + GST_WARNING ("Unknown channels in channel layout - assuming NONE layout"); + none_layout = TRUE; + } + + if (!none_layout && !gst_audio_check_channel_positions (pos, nchannels)) { + GST_ERROR ("Invalid channel layout %" G_GUINT64_FORMAT + " - assuming NONE layout", channel_layout); + none_layout = TRUE; + } + + if (none_layout) { + if (nchannels == 1) { + pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO; + } else if (nchannels == 2) { + pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; + pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; + } else if (channel_layout == 0) { + g_free (pos); + pos = NULL; + } else { + for (i = 0; i < nchannels; i++) { + pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE; + } + } + } + + if (nchannels == 1 && pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER) { + GST_DEBUG ("mono common case; won't set channel positions"); + g_free (pos); + pos = NULL; + } else if (nchannels == 2 && pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT + && pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) { + GST_DEBUG ("stereo common case; won't set channel positions"); + g_free (pos); + pos = NULL; + } + + return pos; +} + +GstCaps* +gst_emul_codectype_to_video_caps (CodecContext *ctx, const char *name, + gboolean encode, CodecElement *codec) +{ + GstCaps *caps; + + GST_DEBUG ("context: %p, codec: %s, encode: %d, codec: %p", + ctx, name, encode, codec); + + if (ctx) { + caps = gst_emul_pixfmt_to_caps (ctx->video.pix_fmt, ctx, name); + } else { + GstCaps *temp; + enum PixelFormat i; + CodecContext ctx = { 0, }; + + caps = gst_caps_new_empty (); + for (i = 0; i <= PIX_FMT_NB; i++) { + temp = gst_emul_pixfmt_to_caps (i, encode ? &ctx : NULL, name); + if (temp != NULL) { + gst_caps_append (caps, temp); + } + } + } + + return caps; +} + +GstCaps * +gst_emul_codectype_to_audio_caps (CodecContext *ctx, const char *name, + gboolean encode, CodecElement *codec) +{ + GstCaps *caps = NULL; + + GST_DEBUG ("context: %p, codec: %s, encode: %d, codec: %p", + ctx, name, encode, codec); +#if 0 + if (codec) { + } +#endif + + if (ctx) { + // FIXME + caps = gst_emul_smpfmt_to_caps (ctx->audio.sample_fmt, ctx, name); +#if 0 + } else if (codec && codec->audio.sample_fmts){ + GstCaps *temp; + int i; + + caps = gst_caps_new_empty (); + for (i = 0; codec->audio.sample_fmts[i] != -1; i++) { + temp = + gst_emul_smpfmt_to_caps (codec->audio.sample_fmts[i], ctx, name); + if (temp != NULL) { + gst_caps_append (caps, temp); + } + } +#endif + } else { + GstCaps *temp; + int i; + CodecContext ctx = { 0, }; + + ctx.audio.channels = -1; + caps = gst_caps_new_empty (); + for (i = 0; i <= SAMPLE_FMT_DBL; i++) { + temp = gst_emul_smpfmt_to_caps (i, encode ? &ctx : NULL, name); + if (temp != NULL) { + gst_caps_append (caps, temp); + } + } + } + + return caps; +} + +GstCaps* +gst_emul_codectype_to_caps (int media_type, CodecContext *ctx, + const char *name, gboolean encode) +{ + GstCaps *caps; + + switch (media_type) { + case AVMEDIA_TYPE_VIDEO: + caps = + gst_emul_codectype_to_video_caps (ctx, name, encode, NULL); + break; + case AVMEDIA_TYPE_AUDIO: + caps = + gst_emul_codectype_to_audio_caps (ctx, name, encode, NULL); + break; + default: + caps = NULL; + break; + } + + return caps; +} + +void +gst_emul_caps_to_pixfmt (const GstCaps *caps, CodecContext *ctx, gboolean raw) +{ + GstStructure *str; + const GValue *fps; + const GValue *par = NULL; + + GST_DEBUG ("converting caps %" GST_PTR_FORMAT, caps); + g_return_if_fail (gst_caps_get_size (caps) == 1); + str = gst_caps_get_structure (caps, 0); + + gst_structure_get_int (str, "width", &ctx->video.width); + gst_structure_get_int (str, "height", &ctx->video.height); + gst_structure_get_int (str, "bpp", &ctx->video.bpp); + + fps = gst_structure_get_value (str, "framerate"); + if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) { + ctx->video.fps_d = gst_value_get_fraction_numerator (fps); + ctx->video.fps_n = gst_value_get_fraction_denominator (fps); + + GST_DEBUG ("setting framerate %d/%d = %lf", + ctx->video.fps_d, ctx->video.fps_n, + 1. * ctx->video.fps_d / ctx->video.fps_n); + } + + par = gst_structure_get_value (str, "pixel-aspect-ratio"); + if (par && GST_VALUE_HOLDS_FRACTION (par)) { + ctx->video.par_n = gst_value_get_fraction_numerator (par); + ctx->video.par_d = gst_value_get_fraction_denominator (par); + } + + if (!raw) { + return; + } + + g_return_if_fail (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)); + + if (strcmp (gst_structure_get_name (str), "video/x-raw-yuv") == 0) { + guint32 fourcc; + + if (gst_structure_get_fourcc (str, "format", &fourcc)) { + switch (fourcc) { + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + ctx->video.pix_fmt = PIX_FMT_YUYV422; + break; + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + ctx->video.pix_fmt = PIX_FMT_YUV420P; + break; + case GST_MAKE_FOURCC ('A', '4', '2', '0'): + ctx->video.pix_fmt = PIX_FMT_YUVA420P; + break; + case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): + ctx->video.pix_fmt = PIX_FMT_YUV411P; + break; + case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): + ctx->video.pix_fmt = PIX_FMT_YUV422P; + break; + case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'): + ctx->video.pix_fmt = PIX_FMT_YUV410P; + break; + } + } + } else if (strcmp (gst_structure_get_name (str), "video/x-raw-rgb") == 0) { + gint bpp = 0, rmask = 0, endianness = 0; + + if (gst_structure_get_int (str, "bpp", &bpp) && + gst_structure_get_int (str, "endianness", &endianness)) { + if (gst_structure_get_int (str, "red_mask", &rmask)) { + switch (bpp) { + case 32: +#if (G_BYTE_ORDER == G_BIG_ENDIAN) + if (rmask == 0x00ff0000) { +#else + if (rmask == 0x00ff0000) { +#endif + ctx->video.pix_fmt = PIX_FMT_RGB32; + } + break; + case 24: + if (rmask == 0x0000FF) { + ctx->video.pix_fmt = PIX_FMT_BGR24; + } else { + ctx->video.pix_fmt = PIX_FMT_RGB24; + } + break; + case 16: + if (endianness == G_BYTE_ORDER) { + ctx->video.pix_fmt = PIX_FMT_RGB565; + } + break; + case 15: + if (endianness == G_BYTE_ORDER) { + ctx->video.pix_fmt = PIX_FMT_RGB555; + } + break; + default: + break; + } + } + } else { + if (bpp == 8) { + ctx->video.pix_fmt = PIX_FMT_PAL8; + // get palette + } + } + } else if (strcmp (gst_structure_get_name (str), "video/x-raw-gray") == 0) { + gint bpp = 0; + + if (gst_structure_get_int (str, "bpp", &bpp)) { + switch (bpp) { + case 8: + ctx->video.pix_fmt = PIX_FMT_GRAY8; + break; + } + } + } +} + +void +gst_emul_caps_to_smpfmt (const GstCaps *caps, CodecContext *ctx, gboolean raw) +{ + GstStructure *str; + gint depth = 0, width = 0, endianness = 0; + gboolean signedness = FALSE; + const gchar *name; + + g_return_if_fail (gst_caps_get_size (caps) == 1); + str = gst_caps_get_structure (caps, 0); + + gst_structure_get_int (str, "channels", &ctx->audio.channels); + gst_structure_get_int (str, "rate", &ctx->audio.sample_rate); + gst_structure_get_int (str, "block_align", &ctx->audio.block_align); + gst_structure_get_int (str, "bitrate", &ctx->audio.bit_rate); + + if (!raw) { + return; + } + +#if 0 + if (!strcmp (name, "audio/x-raw-float")) { + if (gst_structure_get_int (str, "width, &width") && + gst_structure_get_int (str, "endianness", &endianness)) { + if (endianness == G_BYTE_ORDER) { + if (width == 32) { + ctx->audio.sample_fmt = SAMPLE_FMT_FLT; + } else if (width == 64) { + ctx->audio.sample_fmt = SAMPLE_FMT_DBL; + } + } + } + } else { + if (str_structure_get_int (str, "width", &width) && + str_structure_get_int (str, "depth", &depth) && + str_structure_get_int (str, "signed", &signedness) && + str_structure_get_int (str, "endianness", &endianness)) { + if ((endianness == G_BYTE_ORDER) && (signedness == TRUE)) { + if (width == 16) && (depth == 16)) { + ctx->audio.sample_fmt = SAMPLE_FMT_S16; + } else if ((width == 32) && (depth == 32)) { + ctx->audio.sample_fmt = SMPLE_FMT_S32; + } + } + } + } +#endif +} + +void +gst_emul_caps_with_codecname (const char *name, int media_type, + const GstCaps *caps, CodecContext *ctx) +{ + GstStructure *structure; + const GValue *value; + const GstBuffer *buf; + + if (!ctx || !gst_caps_get_size (caps)) { + return; + } + + structure = gst_caps_get_structure (caps, 0); + + if ((value = gst_structure_get_value (structure, "codec_data"))) { + guint size; + guint8 *data; + + buf = GST_BUFFER_CAST (gst_value_get_mini_object (value)); + size = GST_BUFFER_SIZE (buf); + data = GST_BUFFER_DATA (buf); + printf("extradata: %p, size: %d\n", ctx->codecdata, ctx->codecdata_size); + + if (ctx->codecdata) { + g_free (ctx->codecdata); + } + + ctx->codecdata = + g_malloc0 (GST_ROUND_UP_16 (size + FF_INPUT_BUFFER_PADDING_SIZE)); + memcpy (ctx->codecdata, data, size); + ctx->codecdata_size = size; + + if ((strcmp(name, "vc1") == 0) && size > 0 && data[0] == 0) { + ctx->codecdata[0] = (guint8) size; + } + } else if (ctx->codecdata == NULL) { + ctx->codecdata_size = 0; + ctx->codecdata = g_malloc0 (GST_ROUND_UP_16(FF_INPUT_BUFFER_PADDING_SIZE)); + GST_DEBUG ("no extra data.\n"); + } + + if ((strcmp (name, "mpeg4") == 0)) { + const gchar *mime = gst_structure_get_name (structure); + +#if 0 + if (!strcmp (mime, "video/x-divx")) { + ctx->codec_tag = GST_MAKE_FOURCC ('D', 'I', 'V', 'X'); + } else if (!strcmp (mime, "video/x-xvid")) { + ctx->codec_tag = GST_MAKE_FOURCC ('X', 'V', 'I', 'D'); + } else if (!strcmp (mime, "video/x-3ivx")) { + ctx->codec_tag = GST_MAKE_FOURCC ('3', 'I', 'V', '1'); + } else if (!strcmp (mime, "video/mpeg")) { + ctx->codec_tag = GST_MAKE_FOURCC ('m', 'p', '4', 'v'); + } +#endif + } else if (strcmp (name, "h263p") == 0) { + gboolean val; + +#if 0 + if (!gst_structure_get_boolean (structure, "annex-f", &val) || val) { + ctx->flags |= CODEC_FLAG_4MV; + } else { + ctx->flags &= ~CODEC_FLAG_4MV; + } + if ((!gst_structure_get_boolean (structure, "annex-i", &val) || val) && + (!gst_structure_get_boolean (structure, "annex-t", &val) || val) { + ctx->flags |= CODEC_FLAG_AC_PRED; + } else { + ctx->flags &= ~CODEC_FLAG_AC_PRED; + } + if ((!gst_structure_get_boolean (structure, "annex-j", &val) || val) { + ctx->flags |= CODEC_FLAG_LOOP_FILTER; + } else { + ctx->flags &= ~CODEC_FLAG_LOOP_FILTER; + } +#endif + } else { + // TODO + } + + if (!gst_caps_is_fixed (caps)) { + return; + } + + switch (media_type) { + case AVMEDIA_TYPE_VIDEO: + gst_emul_caps_to_pixfmt (caps, ctx, FALSE); + // get_palette + break; + case AVMEDIA_TYPE_AUDIO: + gst_emul_caps_to_smpfmt (caps, ctx, FALSE); + break; + default: + break; + } + +} + +GstCaps * +gst_emul_video_caps_new (CodecContext *ctx, const char *name, + const char *mimetype, const char *fieldname, ...) +{ + GstStructure *structure = NULL; + GstCaps *caps = NULL; + va_list var_args; + gint i; + + GST_LOG ("context: %p, name: %s, mimetype: %s", ctx, name, mimetype); + + if (ctx != NULL && ctx->video.width != -1) { + gint num, denom; + + caps = gst_caps_new_simple (mimetype, + "width", G_TYPE_INT, ctx->video.width, + "height", G_TYPE_INT, ctx->video.height); + + num = ctx->video.fps_d / 1; + denom = ctx->video.fps_d; + + if (!denom) { + GST_LOG ("invalid framerate: %d/0, -> %d/1", num, num); + } + if (gst_util_fraction_compare (num, denom, 1000, 1) > 0) { + GST_LOG ("excessive framerate: %d/%d, -> 0/1", num, denom); + num = 0; + denom = 1; + } + GST_LOG ("setting framerate: %d/%d", num, denom); + gst_caps_set_simple (caps, + "framerate", GST_TYPE_FRACTION, num, denom, NULL); + } else { + if (g_str_has_prefix(name, "h263")) { + /* 128x96, 176x144, 352x288, 704x576, and 1408x1152. slightly reordered + * because we want automatic negotiation to go as close to 320x240 as + * possible. */ + const static gint widths[] = { 352, 704, 176, 1408, 128 }; + const static gint heights[] = { 288, 576, 144, 1152, 96 }; + GstCaps *temp; + gint n_sizes = G_N_ELEMENTS (widths); + + caps = gst_caps_new_empty (); + for (i = 0; i < n_sizes; i++) { + temp = gst_caps_new_simple (mimetype, + "width", G_TYPE_INT, widths[i], + "height", G_TYPE_INT, heights[i], + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + + gst_caps_append (caps, temp); + } + } else { + // TODO + } + } + + /* no fixed caps or special restrictions applied; + * default unfixed setting */ + if (!caps) { + GST_DEBUG ("Creating default caps"); + caps = gst_caps_new_simple (mimetype, + "width", GST_TYPE_INT_RANGE, 16, 4096, + "height", GST_TYPE_INT_RANGE, 16, 4096, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + } + + for (i = 0; i < gst_caps_get_size (caps); i++) { + va_start (var_args, fieldname); + structure = gst_caps_get_structure (caps, i); + gst_structure_set_valist (structure, fieldname, var_args); + va_end (var_args); + } + + return caps; +} + +GstCaps * +gst_emul_audio_caps_new (CodecContext *ctx, const char *name, + const char *mimetype, const char *fieldname, ...) +{ + GstStructure *structure = NULL; + GstCaps *caps = NULL; + gint i; + va_list var_args; + + if (ctx != NULL && ctx->audio.channels != -1) { + GstAudioChannelPosition *pos; + guint64 channel_layout = ctx->audio.channel_layout; + + if (channel_layout == 0) { + const guint64 default_channel_set[] = { + 0, 0, CH_LAYOUT_SURROUND, CH_LAYOUT_QUAD, CH_LAYOUT_5POINT0, + CH_LAYOUT_5POINT1, 0, CH_LAYOUT_7POINT1 + }; + + if (strcmp(name, "ac3") == 0) { + if (ctx->audio.channels > 0 && + ctx->audio.channels < G_N_ELEMENTS (default_channel_set)) { + channel_layout = default_channel_set[ctx->audio.channels - 1]; + } + } else { + // TODO + } + } + + caps = gst_caps_new_simple (mimetype, + "rate", G_TYPE_INT, ctx->audio.sample_rate, + "channels", G_TYPE_INT, ctx->audio.channels, NULL); + + pos = gst_ff_channel_layout_to_gst (channel_layout, ctx->audio.channels); + if (pos != NULL) { + gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos); + g_free (pos); + } + } else { + gint maxchannels = 2; + const gint *rates = NULL; + gint n_rates = 0; + + if (strcmp(name, "aac") == 0) { + maxchannels = 6; + } else if (g_str_has_prefix(name, "ac3")) { + const static gint l_rates[] = { 48000, 44100, 32000 }; + maxchannels = 6; + n_rates = G_N_ELEMENTS (l_rates); + rates = l_rates; + } else { + // TODO + } + + if (maxchannels == 1) { + caps = gst_caps_new_simple(mimetype, + "channels", G_TYPE_INT, maxchannels, NULL); + } else { + caps = gst_caps_new_simple(mimetype, + "channels", GST_TYPE_INT_RANGE, 1, maxchannels, NULL); + } + + if (n_rates) { + GValue list = { 0, }; + GstStructure *structure; + + g_value_init(&list, GST_TYPE_LIST); + for (i = 0; i < n_rates; i++) { + GValue v = { 0, }; + + g_value_init(&v, G_TYPE_INT); + g_value_set_int(&v, rates[i]); + gst_value_list_append_value(&list, &v); + g_value_unset(&v); + } + structure = gst_caps_get_structure(caps, 0); + gst_structure_set_value(structure, "rate", &list); + g_value_unset(&list); + } else { + gst_caps_set_simple(caps, "rate", GST_TYPE_INT_RANGE, 4000, 96000, NULL); + } + } + + for (i = 0; i < gst_caps_get_size (caps); i++) { + va_start (var_args, fieldname); + structure = gst_caps_get_structure (caps, i); + gst_structure_set_valist (structure, fieldname, var_args); + va_end (var_args); + } + + return caps; +} + +GstCaps * +gst_emul_pixfmt_to_caps (enum PixelFormat pix_fmt, CodecContext *ctx, const char *name) +{ + GstCaps *caps = NULL; + + int bpp = 0, depth = 0, endianness = 0; + gulong g_mask = 0, r_mask = 0, b_mask = 0, a_mask = 0; + guint32 fmt = 0; + + switch (pix_fmt) { + case PIX_FMT_YUV420P: + fmt = GST_MAKE_FOURCC ('I', '4', '2', '0'); + break; + case PIX_FMT_YUYV422: + fmt = GST_MAKE_FOURCC ('A', '4', '2', '0'); + break; + case PIX_FMT_RGB24: + bpp = depth = 24; + endianness = G_BIG_ENDIAN; + r_mask = 0xff0000; + g_mask = 0x00ff00; + b_mask = 0x0000ff; + break; + case PIX_FMT_BGR24: + bpp = depth = 24; + endianness = G_BIG_ENDIAN; + r_mask = 0x0000ff; + g_mask = 0x00ff00; + b_mask = 0xff0000; + break; + case PIX_FMT_YUV422P: + fmt = GST_MAKE_FOURCC ('Y', '4', '2', 'B'); + break; + case PIX_FMT_YUV444P: + fmt = GST_MAKE_FOURCC ('Y', '4', '4', '4'); + break; + case PIX_FMT_RGB32: + bpp = 32; + depth = 32; + endianness = G_BIG_ENDIAN; +#if (G_BYTE_ORDER == G_BIG_ENDIAN) + r_mask = 0x00ff0000; + g_mask = 0x0000ff00; + b_mask = 0x000000ff; + a_mask = 0xff000000; +#else + r_mask = 0x00ff0000; + g_mask = 0x0000ff00; + b_mask = 0x000000ff; + a_mask = 0xff000000; +#endif + break; + case PIX_FMT_YUV410P: + fmt = GST_MAKE_FOURCC ('Y', 'U', 'V', '9'); + break; + case PIX_FMT_YUV411P: + fmt = GST_MAKE_FOURCC ('Y', '4', '1', 'b'); + break; + case PIX_FMT_RGB565: + bpp = depth = 16; + endianness = G_BYTE_ORDER; + r_mask = 0xf800; + g_mask = 0x07e0; + b_mask = 0x001f; + break; + case PIX_FMT_RGB555: + bpp = 16; + depth = 15; + endianness = G_BYTE_ORDER; + r_mask = 0x7c00; + g_mask = 0x03e0; + b_mask = 0x001f; + break; + default: + break; + } + + if (caps != NULL) { + if (bpp != 0) { + if (r_mask != 0) { + if (a_mask) { + caps = gst_emul_video_caps_new (ctx, name, "video/x-raw-rgb", + "bpp", G_TYPE_INT, bpp, + "depth", G_TYPE_INT, depth, + "red_mask", G_TYPE_INT, r_mask, + "green_mask", G_TYPE_INT, g_mask, + "blue_mask", G_TYPE_INT, b_mask, + "alpha_mask", G_TYPE_INT, a_mask, + "endianness", G_TYPE_INT, endianness, NULL); + } else { + caps = gst_emul_video_caps_new (ctx, name, "video/x-raw-rgb", + "bpp", G_TYPE_INT, bpp, + "depth", G_TYPE_INT, depth, + "red_mask", G_TYPE_INT, r_mask, + "green_mask", G_TYPE_INT, g_mask, + "blue_mask", G_TYPE_INT, b_mask, + "alpha_mask", G_TYPE_INT, a_mask, + "endianness", G_TYPE_INT, endianness, NULL); + } + } else { + caps = gst_emul_video_caps_new (ctx, name, "video/x-raw-rgb", + "bpp", G_TYPE_INT, bpp, + "depth", G_TYPE_INT, depth, + "endianness", G_TYPE_INT, endianness, NULL); + if (caps && ctx) { + // set paletee + } + } + } else if (fmt) { + caps = gst_emul_video_caps_new (ctx, name, "video/x-raw-yuv", + "format", GST_TYPE_FOURCC, fmt, NULL); + } + } + + if (caps != NULL) { + GST_DEBUG ("caps for pix_fmt=%d: %", GST_PTR_FORMAT, pix_fmt, caps); + } else { + GST_LOG ("No caps found for pix_fmt=%d", pix_fmt); + } + + return caps; +} + +GstCaps * +gst_emul_smpfmt_to_caps (int8_t sample_fmt, CodecContext *ctx, const char *name) +{ + GstCaps *caps = NULL; + + int bpp = 0; + gboolean integer = TRUE; + gboolean signedness = FALSE; + + switch (sample_fmt) { + case SAMPLE_FMT_S16: + signedness = TRUE; + bpp = 16; + break; + case SAMPLE_FMT_S32: + signedness = TRUE; + bpp = 32; + break; + case SAMPLE_FMT_FLT: + integer = FALSE; + bpp = 32; + break; + case SAMPLE_FMT_DBL: + integer = FALSE; + bpp = 64; + break; + default: + break; + } + + if (bpp) { + if (integer) { + caps = gst_emul_audio_caps_new (ctx, name, "audio/x-raw-int", + "signed", G_TYPE_BOOLEAN, signedness, + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, bpp, "depth", G_TYPE_INT, bpp, NULL); + } else { + caps = gst_emul_audio_caps_new (ctx, name, "audio/x-raw-float", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, bpp, NULL); + } + } + + if (caps != NULL) { + GST_LOG ("caps for sample_fmt=%d: %" GST_PTR_FORMAT, sample_fmt, caps); + } else { + GST_LOG ("No caps found for sample_fmt=%d", sample_fmt); + } + + return caps; +} + +GstCaps * +gst_emul_codecname_to_caps (const char *name, CodecContext *ctx, gboolean encode) +{ + GstCaps *caps = NULL; + + GST_LOG ("codec: %s, context: %p, encode: %d", name, ctx, encode); + + if (strcmp(name, "mpegvideo") == 0) { + caps = gst_emul_video_caps_new (ctx, name, "video/mpeg", + "mpegversion", G_TYPE_INT, 1, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + } else if (strcmp(name, "h263") == 0) { + if (encode) { + caps = gst_emul_video_caps_new (ctx, name, "video/x-h263", + "variant", G_TYPE_STRING, "itu", NULL); + } else { + caps = gst_emul_video_caps_new (ctx, name, "video/x-h263", + "variant", G_TYPE_STRING, "itu", + "h263version", G_TYPE_STRING, "h263", NULL); + } + } else if (strcmp(name, "h263p") == 0) { + caps = gst_emul_video_caps_new (ctx, name, "video/x-h263", + "variant", G_TYPE_STRING, "itu", + "h263version", G_TYPE_STRING, "h263p", NULL); +#if 0 + if (encode && ctx) { + gst_caps_set_simple (caps, + "annex-f", G_TYPE_BOOLEAN, ctx->flags & CODEC_FLAG_4MV, + "annex-j", G_TYPE_BOOLEAN, ctx->flags & CODEC_FLAG_LOOP_FILTER, + "annex-i", G_TYPE_BOOLEAN, ctx->flags & CODEC_FLAG_AC_PRED, + "annex-t", G_TYPE_BOOLEAN, ctx->flags & CODEC_FLAG_AC_PRED, + NULL); + } +#endif + } else if (strcmp(name, "mpeg4") == 0) { + if (encode && ctx != NULL) { + // TODO + } else { + caps = gst_emul_video_caps_new (ctx, name, "video/mpeg", + "mpegversion", G_TYPE_INT, 4, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + if (encode) { + caps = gst_emul_video_caps_new (ctx, name, "video/mpeg", + "mpegversion", G_TYPE_INT, 4, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + } else { + gst_caps_append (caps, gst_emul_video_caps_new (ctx, name, + "video/x-divx", "divxversion", GST_TYPE_INT_RANGE, 4, 5, NULL)); + gst_caps_append (caps, gst_emul_video_caps_new (ctx, name, + "video/x-xvid", NULL)); + gst_caps_append (caps, gst_emul_video_caps_new (ctx, name, + "video/x-3ivx", NULL)); + } + } + } else if (strcmp(name, "h264") == 0) { + caps = gst_emul_video_caps_new (ctx, name, "video/x-h264", NULL); + } else if (g_str_has_prefix(name, "msmpeg4")) { + // msmpeg4v1,m msmpeg4v2, msmpeg4 + gint version; + + if (strcmp(name, "msmpeg4v1") == 0) { + version = 41; + } else if (strcmp(name, "msmpeg4v2") == 0) { + version = 42; + } else { + version = 43; + } + + caps = gst_emul_video_caps_new (ctx, name, "video/x-msmpeg", + "msmpegversion", G_TYPE_INT, version, NULL); + if (!encode && !strcmp(name, "msmpeg4")) { + gst_caps_append (caps, gst_emul_video_caps_new (ctx, name, + "video/x-divx", "divxversion", G_TYPE_INT, 3, NULL)); + } + } else if (strcmp(name, "wmv3") == 0) { + caps = gst_emul_video_caps_new (ctx, name, "video/x-wmv", + "wmvversion", G_TYPE_INT, 3, NULL); + } else if (strcmp(name, "vc1") == 0) { + caps = gst_emul_video_caps_new (ctx, name, "video/x-wmv", + "wmvversion", G_TYPE_INT, 3, "format", GST_TYPE_FOURCC, + GST_MAKE_FOURCC ('W', 'V', 'C', '1'), NULL); +#if 0 + } else if (strcmp(name, "vp3") == 0) { + mime_type = g_strdup ("video/x-vp3"); + } else if (strcmp(name, "vp8") == 0) { + mime_type = g_strdup ("video/x-vp8"); +#endif + } else if (strcmp(name, "aac") == 0) { + caps = gst_emul_audio_caps_new (ctx, name, "audio/mpeg", NULL); + if (!encode) { + GValue arr = { 0, }; + GValue item = { 0, }; + + g_value_init (&arr, GST_TYPE_LIST); + g_value_init (&item, G_TYPE_INT); + g_value_set_int (&item, 2); + gst_value_list_append_value (&arr, &item); + g_value_set_int (&item, 4); + gst_value_list_append_value (&arr, &item); + g_value_unset (&item); + + gst_caps_set_value (caps, "mpegversion", &arr); + g_value_unset (&arr); + + g_value_init (&arr, GST_TYPE_LIST); + g_value_init (&item, G_TYPE_STRING); + g_value_set_string (&item, "raw"); + gst_value_list_append_value (&arr, &item); + g_value_set_string (&item, "adts"); + gst_value_list_append_value (&arr, &item); + g_value_set_string (&item, "adif"); + gst_value_list_append_value (&arr, &item); + g_value_unset (&item); + + gst_caps_set_value (caps, "stream-format", &arr); + g_value_unset (&arr); + } else { + gst_caps_set_simple (caps, "mpegversion", G_TYPE_INT, 4, + "stream-format", G_TYPE_STRING, "raw", + "base-profile", G_TYPE_STRING, "lc", NULL); +#if 1 + if (ctx && ctx->codecdata_size > 0) { + gst_codec_utils_aac_caps_set_level_and_profile (caps, + ctx->codecdata, ctx->codecdata_size); + } +#endif + } + } else if (strcmp(name, "ac3") == 0) { + caps = gst_emul_audio_caps_new (ctx, name, "audio/x-ac3", NULL); + } else if (strcmp(name, "mp3") == 0) { +#if 0 + if (encode) { + caps = gst_emul_audio_caps_new (ctx, name, "audio/mpeg", + "mpegversion", G_TYPE_INT, 1, + "layer", GST_TYPE_INT_RANGE, 1, 3, NULL); + } else { +#endif + caps = gst_caps_new_simple("audio/mpeg", + "mpegversion", G_TYPE_INT, 1, + "layer", GST_TYPE_INT_RANGE, 1, 3, NULL); +// } + } else if (strcmp(name, "mp3adu") == 0) { + gchar *mime_type; + + mime_type = g_strdup_printf ("audio/x-gst_ff-%s", name); + caps = gst_emul_audio_caps_new (ctx, name, mime_type, NULL); + + if (mime_type) { + g_free(mime_type); + } + } else if (g_str_has_prefix(name, "wmav")) { + gint version = 1; + if (strcmp(name, "wmav2") == 0) { + version = 2; + } + caps = gst_emul_audio_caps_new (ctx, name, "audio/x-wma", "wmaversion", + G_TYPE_INT, version, "block_align", GST_TYPE_INT_RANGE, 0, G_MAXINT, + "bitrate", GST_TYPE_INT_RANGE, 0, G_MAXINT, NULL); + } else { + GST_ERROR("failed to new caps for %s.\n", name); + } + + return caps; +} + +typedef struct PixFmtInfo +{ + uint8_t x_chroma_shift; /* X chroma subsampling factor is 2 ^ shift */ + uint8_t y_chroma_shift; /* Y chroma subsampling factor is 2 ^ shift */ +} PixFmtInfo; + +static PixFmtInfo pix_fmt_info[PIX_FMT_NB]; + +#define GEN_MASK(x) ((1<<(x))-1) +#define ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) & ~GEN_MASK(x)) +#define ROUND_UP_2(x) ROUND_UP_X(x, 1) +#define ROUND_UP_4(x) ROUND_UP_X(x, 2) +#define ROUND_UP_8(x) ROUND_UP_X(x, 3) +#define DIV_ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) >> (x)) + +void +gst_emul_init_pix_fmt_info (void) +{ + pix_fmt_info[PIX_FMT_YUV420P].x_chroma_shift = 1, + pix_fmt_info[PIX_FMT_YUV420P].y_chroma_shift = 1; + + pix_fmt_info[PIX_FMT_YUV422P].x_chroma_shift = 1; + pix_fmt_info[PIX_FMT_YUV422P].y_chroma_shift = 0; + + pix_fmt_info[PIX_FMT_YUV444P].x_chroma_shift = 0; + pix_fmt_info[PIX_FMT_YUV444P].y_chroma_shift = 0; + + pix_fmt_info[PIX_FMT_YUYV422].x_chroma_shift = 1; + pix_fmt_info[PIX_FMT_YUYV422].y_chroma_shift = 0; + + pix_fmt_info[PIX_FMT_YUV410P].x_chroma_shift = 2; + pix_fmt_info[PIX_FMT_YUV410P].y_chroma_shift = 2; + + pix_fmt_info[PIX_FMT_YUV411P].x_chroma_shift = 2; + pix_fmt_info[PIX_FMT_YUV411P].y_chroma_shift = 0; + + /* RGB formats */ + pix_fmt_info[PIX_FMT_RGB24].x_chroma_shift = 0; + pix_fmt_info[PIX_FMT_RGB24].y_chroma_shift = 0; + + pix_fmt_info[PIX_FMT_BGR24].x_chroma_shift = 0; + pix_fmt_info[PIX_FMT_BGR24].y_chroma_shift = 0; + + pix_fmt_info[PIX_FMT_RGB32].x_chroma_shift = 0; + pix_fmt_info[PIX_FMT_RGB32].y_chroma_shift = 0; + + pix_fmt_info[PIX_FMT_RGB565].x_chroma_shift = 0; + pix_fmt_info[PIX_FMT_RGB565].y_chroma_shift = 0; + + pix_fmt_info[PIX_FMT_RGB555].x_chroma_shift = 0; + pix_fmt_info[PIX_FMT_RGB555].y_chroma_shift = 0; +} + +int +gst_emul_avpicture_size (int pix_fmt, int width, int height) +{ + int size, w2, h2, size2; + int stride, stride2; + int fsize; + PixFmtInfo *pinfo; + + pinfo = &pix_fmt_info[pix_fmt]; + + switch (pix_fmt) { + case PIX_FMT_YUV420P: + case PIX_FMT_YUV422P: + case PIX_FMT_YUV444P: + case PIX_FMT_YUV410P: + case PIX_FMT_YUV411P: + stride = ROUND_UP_4(width); + h2 = ROUND_UP_X(height, pinfo->y_chroma_shift); + size = stride * h2; + w2 = DIV_ROUND_UP_X(width, pinfo->x_chroma_shift); + stride2 = ROUND_UP_4(w2); + h2 = DIV_ROUND_UP_X(height, pinfo->y_chroma_shift); + size2 = stride2 * h2; + fsize = size + 2 * size2; + break; + case PIX_FMT_RGB24: + case PIX_FMT_BGR24: + stride = ROUND_UP_4 (width * 3); + fsize = stride * height; + break; + case PIX_FMT_RGB32: + stride = width * 4; + fsize = stride * height; + break; + case PIX_FMT_RGB555: + case PIX_FMT_RGB565: + stride = ROUND_UP_4 (width * 2); + fsize = stride * height; + break; + default: + fsize = -1; + break; + } + + return fsize; +} diff --git a/src/gstemulutils.h b/src/gstemulutils.h new file mode 100644 index 0000000..b07076e --- /dev/null +++ b/src/gstemulutils.h @@ -0,0 +1,108 @@ +/* + * GStreamer codec plugin for Tizen Emulator. + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * KiTae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef __GST_EMUL_UTIL_H__ +#define __GST_EMUL_UTIL_H__ + +#include "gstemulcommon.h" + +// FFmpeg +#include "audioconvert.h" + +/* Audio channel masks */ +#define CH_FRONT_LEFT AV_CH_FRONT_LEFT +#define CH_FRONT_RIGHT AV_CH_FRONT_RIGHT +#define CH_FRONT_CENTER AV_CH_FRONT_CENTER +#define CH_LOW_FREQUENCY AV_CH_LOW_FREQUENCY +#define CH_BACK_LEFT AV_CH_BACK_LEFT +#define CH_BACK_RIGHT AV_CH_BACK_RIGHT +#define CH_FRONT_LEFT_OF_CENTER AV_CH_FRONT_LEFT_OF_CENTER +#define CH_FRONT_RIGHT_OF_CENTER AV_CH_FRONT_RIGHT_OF_CENTER +#define CH_BACK_CENTER AV_CH_BACK_CENTER +#define CH_SIDE_LEFT AV_CH_SIDE_LEFT +#define CH_SIDE_RIGHT AV_CH_SIDE_RIGHT +#define CH_TOP_CENTER AV_CH_TOP_CENTER +#define CH_TOP_FRONT_LEFT AV_CH_TOP_FRONT_LEFT +#define CH_TOP_FRONT_CENTER AV_CH_TOP_FRONT_CENTER +#define CH_TOP_FRONT_RIGHT AV_CH_TOP_FRONT_RIGHT +#define CH_TOP_BACK_LEFT AV_CH_TOP_BACK_LEFT +#define CH_TOP_BACK_CENTER AV_CH_TOP_BACK_CENTER +#define CH_TOP_BACK_RIGHT AV_CH_TOP_BACK_RIGHT +#define CH_STEREO_LEFT AV_CH_STEREO_LEFT +#define CH_STEREO_RIGHT AV_CH_STEREO_RIGHT + +/** Channel mask value used for AVCodecContext.request_channel_layout + to indicate that the user requests the channel order of the decoder output + to be the native codec channel order. */ +#define CH_LAYOUT_NATIVE AV_CH_LAYOUT_NATIVE + +/* Audio channel convenience macros */ +#define CH_LAYOUT_MONO AV_CH_LAYOUT_MONO +#define CH_LAYOUT_STEREO AV_CH_LAYOUT_STEREO +#define CH_LAYOUT_2_1 AV_CH_LAYOUT_2_1 +#define CH_LAYOUT_SURROUND AV_CH_LAYOUT_SURROUND +#define CH_LAYOUT_4POINT0 AV_CH_LAYOUT_4POINT0 +#define CH_LAYOUT_2_2 AV_CH_LAYOUT_2_2 +#define CH_LAYOUT_QUAD AV_CH_LAYOUT_QUAD +#define CH_LAYOUT_5POINT0 AV_CH_LAYOUT_5POINT0 +#define CH_LAYOUT_5POINT1 AV_CH_LAYOUT_5POINT1 +#define CH_LAYOUT_5POINT0_BACK AV_CH_LAYOUT_5POINT0_BACK +#define CH_LAYOUT_5POINT1_BACK AV_CH_LAYOUT_5POINT1_BACK +#define CH_LAYOUT_7POINT0 AV_CH_LAYOUT_7POINT0 +#define CH_LAYOUT_7POINT1 AV_CH_LAYOUT_7POINT1 +#define CH_LAYOUT_7POINT1_WIDE AV_CH_LAYOUT_7POINT1_WIDE +#define CH_LAYOUT_STEREO_DOWNMIX AV_CH_LAYOUT_STEREO_DOWNMIX + +GstCaps *gst_emul_codectype_to_video_caps (CodecContext *ctx, const char *name, + gboolean encode, CodecElement *codec); + +GstCaps *gst_emul_codectype_to_audio_caps (CodecContext *ctx, const char *name, + gboolean encode, CodecElement *codec); + + +GstCaps *gst_emul_codectype_to_caps (int media_type, CodecContext *ctx, + const char *name, gboolean encode); + +void gst_emul_caps_with_codecname (const char *name, int media_type, + const GstCaps *caps, CodecContext *ctx); + +GstCaps *gst_emul_video_caps_new (CodecContext *ctx, const char *name, + const char *mimetype, const char *fieldname, ...); + +GstCaps *gst_emul_audio_caps_new (CodecContext *ctx, const char *name, + const char *mimetype, const char *fieldname, ...); + +GstCaps *gst_emul_pixfmt_to_caps (enum PixelFormat pix_fmt, CodecContext *ctx, const char *name); + +GstCaps *gst_emul_smpfmt_to_caps (int8_t sample_fmt, CodecContext *ctx, const char *name); + +GstCaps *gst_emul_codecname_to_caps (const char *name, CodecContext *ctx, gboolean encode); + +#endif