# 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, #
##############################################################################
# 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
+++ /dev/null
-/*
- * GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2003> David Schleef <ds@schleef.org>
- * 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.
- *
- * <refsect2>
- * <title>Example launch line</title>
- * |[
- * gst-launch -v -m audiotestsrc ! plugin ! autoaudiosink
- * ]|
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include <gst/audio/audio.h>
-#include <gst/audio/gstaudiofilter.h>
-#include <string.h>
-
-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/"
-);
/*
* 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 <kt920.kim@samsung.com>
* SeokYeon Hwang <syeon.hwang@samsung.com>
* YeongKyoon Lee <yeongkyoon.lee@samsung.com>
*
*/
-#include <gst/gst.h>
+#include "gstemulcommon.h"
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
#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"
)
--- /dev/null
+/*
+ * GStreamer codec plugin for Tizen Emulator.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * GStreamer codec plugin for Tizen Emulator.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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__ */
+/*
+ * GStreamer codec plugin for Tizen Emulator.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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__
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <glib.h>
#include <gst/gst.h>
+#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,
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,
* e.g. FFmpeg, x264, libvpx and etc.
*/
enum {
- FFMPEG_TYPE = 1,
+ FFMPEG_TYPE = 1,
};
G_END_DECLS
+++ /dev/null
-/*
- * Emulator
- *
- * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact:
- * KiTae Kim <kt920.kim@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * 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 <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <gst/gst.h>
-//#include <glib.h>
-//#include <glib/gprintf.h>
-#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 <kt920.kim@samsung.com>"); // 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;
-}
/*
* 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 <kt920.kim@samsung.com>
* 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 <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <gst/gst.h>
+
#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);
}
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;
}
/*
* 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 <kt920.kim@samsung.com>
* 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
--- /dev/null
+/*
+ * GStreamer codec plugin for Tizen Emulator.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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 <kt920.kim@samsung.com>"); // 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;
+}
+
--- /dev/null
+/*
+ * GStreamer codec plugin for Tizen Emulator.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <gst/gst.h>
+#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 <kt920.kim@samsung.com>");
+ 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;
+}
--- /dev/null
+/*
+ * GStreamer codec plugin for Tizen Emulator.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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 <gst/audio/multichannel.h>
+#include <gst/pbutils/codec-utils.h>
+
+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;
+}
--- /dev/null
+/*
+ * GStreamer codec plugin for Tizen Emulator.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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