GST_REQUIRED=0.10.16
GSTPB_REQUIRED=0.10.16
-AC_CONFIG_SRCDIR([src/gstemul.c])
+AC_CONFIG_SRCDIR([src/gstmaru.c])
AC_CONFIG_HEADERS([config.h])
dnl required version of automake
+* Wed Sep 11 12:32:26 UTC 2013 Kitae Kim <kt920.kim@samsung.com>
+- changed a way to use device memory effectively.
+
* Wed Aug 21 06:04:11 UTC 2013 Kitae Kim <kt920.kim@samsung.com>
- fixed prevent issues.
- fixed prevent issues.
* Fri Jun 21 11:49:35 UTC 2013 Kitae Kim <kt920.kim@samsung.com>
-- improved architecture of gstreamer codec plugin.
Name: gst-plugins-emulator
-Version: 0.1.4
+Version: 0.1.5
Release: 2
Summary: GStreamer Streaming-media framework plug-in for Tizen emulator.
Group: TO_BE/FILLED_IN
##############################################################################
# sources used to compile this plug-in
-libgstemul_la_SOURCES = gstemul.c \
- gstemulutils.c \
- gstemuldec.c \
- gstemulenc.c \
- gstemulapi.c \
- gstemuldev.c \
- gstemulapi2.c
+libgstemul_la_SOURCES = gstmaru.c \
+ gstmaruutils.c \
+ gstmarudec.c \
+ gstmaruenc.c \
+ gstmaruinterface.c \
+ gstmarudevice.c \
+ gstmarumem.c
# compiler and linker flags used to compile this plugin, set in configure.ac
libgstemul_la_CFLAGS = $(GST_CFLAGS) -g
libgstemul_la_LIBTOOLFLAGS = --tag=disable-static
# headers we need but don't want installed
-#noinst_HEADERS = gstemul.h
+#noinst_HEADERS = gstmaru.h
+++ /dev/null
-/*
- * 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.
- */
-
-/* First, include the header file for the plugin, to bring in the
- * object definition and other useful things.
- */
-
-/*
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "gstemulcommon.h"
-
-GST_DEBUG_CATEGORY (emul_debug);
-
-#define GST_TYPE_EMULDEC \
- (gst_emul_dec_get_type())
-#define GST_EMULDEC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EMULDEC,GstEmulDec))
-#define GST_EMULDEC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EMULDEC,GstEmulDecClass))
-#define GST_IS_EMULDEC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EMULDEC))
-#define GST_IS_EMULDEC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EMULDEC))
-
-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 = 0, size = 0;
- int version = 0;
- int data_length = 0;
- int i, elem_cnt = 0;
- void *buffer = NULL;
- CodecElement *elem = NULL;
-
- fd = open (CODEC_DEV, O_RDWR);
- if (fd < 0) {
- perror ("[gst-emul] failed to open codec device");
- return FALSE;
- }
-
- ioctl (fd, CODEC_CMD_GET_VERSION, &version);
- if (version != CODEC_VER) {
- CODEC_LOG (INFO, "version conflict between device: %d, plugin: %d\n",
- version, CODEC_VER);
- close (fd);
- return FALSE;
- }
-
- buffer = mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (!buffer) {
- perror ("[gst-emul] failure memory mapping.");
- close (fd);
- return FALSE;
- }
-
- CODEC_LOG (DEBUG, "request a device to get codec element.\n");
- if (ioctl(fd, CODEC_CMD_GET_ELEMENT, NULL) < 0) {
- perror ("[gst-emul] failed to get codec elements");
- munmap (buffer, 4096);
- close (fd);
- return FALSE;
- }
-
- memcpy(&data_length, (uint8_t *)buffer, sizeof(data_length));
- size += sizeof(data_length);
-
- elem = g_malloc0 (data_length);
- if (!elem) {
- CODEC_LOG (ERR, "Failed to allocate memory.\n");
- munmap (buffer, 4096);
- close (fd);
- return FALSE;
- }
-
- memcpy (elem, (uint8_t *)buffer + size, data_length);
-
- elem_cnt = data_length / sizeof(CodecElement);
- for (i = 0; i < elem_cnt; i++) {
- codec_element = g_list_append (codec_element, &elem[i]);
- }
-
- munmap (buffer, 4096);
- close (fd);
-
- return TRUE;
-}
-
-static gboolean
-plugin_init (GstPlugin *plugin)
-{
- GST_DEBUG_CATEGORY_INIT (emul_debug,
- "tizen-emul", 0, "Tizen Emulator Codec Elements");
-
- gst_emul_init_pix_fmt_info ();
-
- if (!gst_emul_codec_element_init ()) {
- GST_ERROR ("failed to get codec elements from QEMU");
- return FALSE;
- }
-
- if (!gst_emuldec_register (plugin, codec_element)) {
- GST_ERROR ("failed to register decoder elements");
- return FALSE;
- }
- if (!gst_emulenc_register (plugin, codec_element)) {
- GST_ERROR ("failed to register encoder elements");
- return FALSE;
- }
-
-#if 0
- while ((codec_element = g_list_next (codec_element))) {
- g_list_free (codec_element);
- }
-#endif
-
- return TRUE;
-}
-
-#ifndef PACKAGE
-#define PACKAGE "gst-plugins-emulator"
-#endif
-
-GST_PLUGIN_DEFINE (
- GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "tizen-emul",
- "Codecs for Tizen Emulator",
- plugin_init,
- "0.1.1",
- "LGPL",
- "gst-plugins-emulator",
- "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 "gstemulapi2.h"
-#include "gstemuldev.h"
-
-extern int device_fd;
-extern gpointer device_mem;
-
-struct mem_info {
- gpointer start;
- uint32_t offset;
-};
-
-typedef struct _CodecHeader {
- int32_t api_index;
- uint32_t mem_offset;
-} CodecHeader;
-
-static int
-_codec_header (int32_t api_index, uint32_t mem_offset, uint8_t *device_buf)
-{
- CodecHeader header = { 0 };
-
- CODEC_LOG (DEBUG, "enter, %s\n", __func__);
-
- header.api_index = api_index;
- header.mem_offset = mem_offset;
-
- memcpy(device_buf, &header, sizeof(header));
-
- CODEC_LOG (DEBUG, "leave, %s\n", __func__);
-
- return sizeof(header);
-}
-
-static void
-_codec_write_to_qemu (int32_t ctx_index, int32_t api_index,
- uint32_t mem_offset, int fd)
-{
- CodecIOParams ioparam;
-
- memset(&ioparam, 0, sizeof(ioparam));
- ioparam.api_index = api_index;
- ioparam.ctx_index = ctx_index;
- ioparam.mem_offset = mem_offset;
- if (write (fd, &ioparam, 1) < 0) {
- fprintf (stderr, "%s, failed to write copy data.\n", __func__);
- }
-}
-
-#define SMALL_BUFFER (256 * 1024)
-#define MEDIUM_BUFFER (2 * 1024 * 1024)
-#define LARGE_BUFFER (4 * 1024 * 1024)
-
-static struct mem_info
-secure_device_mem (guint buf_size)
-{
- int ret = 0;
- uint32_t mem_offset = 0, cmd;
- struct mem_info info;
-
- CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-
- if (buf_size < SMALL_BUFFER) {
- cmd = CODEC_CMD_S_SECURE_BUFFER;
- CODEC_LOG (DEBUG, "small buffer size\n");
- } else if (buf_size < MEDIUM_BUFFER) {
- // HD Video(2MB)
- cmd = CODEC_CMD_M_SECURE_BUFFER;
- CODEC_LOG (DEBUG, "HD buffer size\n");
- } else {
- // FULL HD Video(4MB)
- cmd = CODEC_CMD_L_SECURE_BUFFER;
- CODEC_LOG (DEBUG, "FULL HD buffer size\n");
- }
-
- ret = ioctl (device_fd, cmd, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed to get available buffer\n");
- // FIXME:
- } else {
- if (mem_offset == (LARGE_BUFFER * 8)) {
- CODEC_LOG (ERR, "acquired memory is over!!\n");
- } else {
- info.start = (gpointer)((uint32_t)device_mem + mem_offset);
- info.offset = mem_offset;
-
- CODEC_LOG (DEBUG, "acquire device_memory: 0x%x\n", mem_offset);
- }
- }
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-
- return info;
-}
-
-static void
-release_device_mem (gpointer start)
-{
- int ret;
- uint32_t offset = start - device_mem;
-
- CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-
- CODEC_LOG (DEBUG, "release device_mem start: %p, offset: 0x%x\n", start, offset);
- ret = ioctl (device_fd, CODEC_CMD_RELEASE_MEMORY, &offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed to release buffer\n");
- }
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-}
-
-static void
-codec_buffer_free (gpointer start)
-{
- CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-
- release_device_mem (start);
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-}
-
-GstFlowReturn
-codec_buffer_alloc (GstPad *pad, guint64 offset, guint size,
- GstCaps *caps, GstBuffer **buf)
-{
- struct mem_info info;
-
- CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-
- *buf = gst_buffer_new ();
-
- info = secure_device_mem (size);
-
- CODEC_LOG (DEBUG, "memory start: 0x%p, offset 0x%x\n",
- info.start, info.offset);
-
- GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = info.start;
- GST_BUFFER_SIZE (*buf) = size;
- GST_BUFFER_FREE_FUNC (*buf) = codec_buffer_free;
- GST_BUFFER_OFFSET (*buf) = offset;
-
- if (caps) {
- gst_buffer_set_caps (*buf, caps);
- }
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-
- return GST_FLOW_OK;
-}
-
-int
-codec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
-{
- int fd, ret = 0;
- int opened, size = 0;
- uint8_t *mmapbuf = NULL;
- uint32_t meta_offset = 0;
-
- CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-
- fd = dev->fd;
- if (fd < 0) {
- GST_ERROR ("failed to get %s fd.\n", CODEC_DEV);
- return -1;
- }
-
- mmapbuf = (uint8_t *)dev->buf;
- if (!mmapbuf) {
- GST_ERROR ("failed to get mmaped memory address.\n");
- return -1;
- }
-
- ret = ioctl(fd, CODEC_CMD_GET_CONTEXT_INDEX, &ctx->index);
- if (ret < 0) {
- GST_ERROR ("failed to get context index\n");
- return -1;
- }
- CODEC_LOG (INFO, "get context index: %d\n", ctx->index);
-
- meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
- CODEC_LOG (DEBUG,
- "init. ctx: %d meta_offset = 0x%x\n", ctx->index, meta_offset);
-
-// size = _codec_header (CODEC_INIT, 0, mmapbuf + meta_offset);
- size = 8;
- _codec_init_meta_to (ctx, codec, mmapbuf + meta_offset + size);
-
- _codec_write_to_qemu (ctx->index, CODEC_INIT, 0, fd);
-
- CODEC_LOG (DEBUG,
- "init. ctx: %d meta_offset = 0x%x, size: %d\n", ctx->index, meta_offset, size);
-
-#if 0
- if (codec->media_type == AVMEDIA_TYPE_AUDIO) {
- CODEC_LOG (DEBUG,
- "opened: %d, audio_sample_fmt: %d\n",
- *(int *)(mmapbuf + meta_offset + size),
- *(int *)(mmapbuf + meta_offset + size + 4));
- }
-#endif
-
- opened =
- _codec_init_meta_from (ctx, codec->media_type, mmapbuf + meta_offset + size);
- ctx->codec= codec;
-
- CODEC_LOG (DEBUG, "leave: %s, opened: %d\n", __func__, opened);
-
- return opened;
-}
-
-void
-codec_deinit (CodecContext *ctx, CodecDevice *dev)
-{
- int fd;
- void *mmapbuf = NULL;
-
- CODEC_LOG (DEBUG, "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_LOG (INFO, "close. context index: %d\n", ctx->index);
- _codec_write_to_qemu (ctx->index, CODEC_DEINIT, 0, fd);
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-}
-
-int
-codec_decode_video (CodecContext *ctx, uint8_t *in_buf, int in_size,
- gint idx, gint64 in_offset, GstBuffer **out_buf,
- int *got_picture_ptr, CodecDevice *dev)
-{
- int fd, len = 0;
- int ret, size = 0;
- uint8_t *mmapbuf = NULL;
- uint32_t mem_offset = 0, meta_offset = 0;
-
- CODEC_LOG (DEBUG, "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;
- }
-
- ret = ioctl (fd, CODEC_CMD_S_SECURE_BUFFER, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR,
- "decode_audio. failed to get available memory to write inbuf\n");
- return -1;
- }
-// CODEC_LOG (INFO, "write, decode_video. mem_offset = 0x%x\n", mem_offset);
-
- meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
- CODEC_LOG (DEBUG, "decode_video. meta mem_offset = 0x%x\n", meta_offset);
-
-// size = _codec_header (CODEC_DECODE_VIDEO, mem_offset, mmapbuf + meta_offset);
- size = 8;
- _codec_decode_video_meta_to (in_size, idx, in_offset, mmapbuf + meta_offset + size);
- _codec_decode_video_inbuf (in_buf, in_size, mmapbuf + mem_offset);
-
- dev->mem_info.offset = mem_offset;
- _codec_write_to_qemu (ctx->index, CODEC_DECODE_VIDEO, mem_offset, fd);
-
- // after decoding video, no need to get outbuf.
- len =
- _codec_decode_video_meta_from (&ctx->video, got_picture_ptr, mmapbuf + meta_offset + size);
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-
- return len;
-}
-
-void
-codec_picture_copy (CodecContext *ctx, uint8_t *pict,
- uint32_t pict_size, CodecDevice *dev)
-{
- int fd, ret = 0;
- void *mmapbuf = NULL;
-
- CODEC_LOG (DEBUG, "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_LOG (DEBUG, "pict_size: %d\n", pict_size);
-
-// if (pict_size < MEDIUM_BUFFER) {
- if (pict_size < (SMALL_BUFFER)) {
- dev->mem_info.offset = (uint32_t)pict - (uint32_t)mmapbuf;
- CODEC_LOG (DEBUG, "pict: %p , device_mem: %p\n", pict, mmapbuf);
- CODEC_LOG (DEBUG, "picture_copy, mem_offset = 0x%x\n", dev->mem_info.offset);
- }
-
- _codec_write_to_qemu (ctx->index, CODEC_PICTURE_COPY,
- dev->mem_info.offset, fd);
-// if (pict_size < MEDIUM_BUFFER) {
- if (pict_size < SMALL_BUFFER) {
- CODEC_LOG (DEBUG,
- "set the mem_offset as outbuf: 0x%x\n", dev->mem_info.offset);
- ret = ioctl (fd, CODEC_CMD_USE_DEVICE_MEM, &(dev->mem_info.offset));
- if (ret < 0) {
- // FIXME:
- }
- } else if (pict_size < MEDIUM_BUFFER) {
- uint32_t mem_offset = 0;
- CODEC_LOG (DEBUG, "require to use medium size of memory\n");
-
- ret = ioctl (fd, CODEC_CMD_REQ_FROM_MEDIUM_MEMORY, &mem_offset);
- if (ret < 0) {
- return;
- }
- CODEC_LOG (DEBUG, "picture_copy, mem_offset = 0x%x\n", mem_offset);
-
- memcpy (pict, mmapbuf + mem_offset, pict_size);
-
- ret = ioctl(fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed release used memory\n");
- }
- } else {
- uint32_t mem_offset = 0;
- CODEC_LOG (DEBUG, "require to use large size of memory\n");
-
- ret = ioctl (fd, CODEC_CMD_REQ_FROM_LARGE_MEMORY, &mem_offset);
- if (ret < 0) {
- return;
- }
- CODEC_LOG (DEBUG, "picture_copy, mem_offset = 0x%x\n", mem_offset);
-
- memcpy (pict, mmapbuf + mem_offset, pict_size);
-
- ret = ioctl(fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed release used memory\n");
- }
- }
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-}
-
-int
-codec_decode_audio (CodecContext *ctx, int16_t *samples,
- int *have_data, uint8_t *in_buf,
- int in_size, CodecDevice *dev)
-{
- int fd, len = 0;
- int ret, size = 0;
- uint8_t *mmapbuf = NULL;
- uint32_t mem_offset = 0, meta_offset = 0;
-
- CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-
- fd = dev->fd;
- if (fd < 0) {
- GST_ERROR("failed to get %s fd\n", CODEC_DEV);
- return -1;
- }
-
- mmapbuf = (uint8_t *)dev->buf;
- if (!mmapbuf) {
- GST_ERROR("failed to get mmaped memory address\n");
- return -1;
- }
-
- ret = ioctl (fd, CODEC_CMD_S_SECURE_BUFFER, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR,
- "decode_audio. failed to get available memory to write inbuf\n");
- return -1;
- }
-// CODEC_LOG (INFO, "decode audio1 mem_offset = 0x%x\n", mem_offset);
-
- meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
- CODEC_LOG (DEBUG, "decode_audio. meta_offset = 0x%x\n", meta_offset);
-
-// size = _codec_header (CODEC_DECODE_AUDIO, mem_offset, mmapbuf + meta_offset);
- size = 8;
- _codec_decode_audio_meta_to (in_size, mmapbuf + meta_offset + size);
- _codec_decode_audio_inbuf (in_buf, in_size, mmapbuf + mem_offset);
-
- dev->mem_info.offset = mem_offset;
- _codec_write_to_qemu (ctx->index, CODEC_DECODE_AUDIO, mem_offset, fd);
-
- ret = ioctl (fd, CODEC_CMD_REQ_FROM_SMALL_MEMORY, &mem_offset);
- if (ret < 0) {
- return -1;
- }
-// CODEC_LOG (INFO, "decode audio2. mem_offset = 0x%x\n", mem_offset);
-
- len =
- _codec_decode_audio_meta_from (&ctx->audio, have_data, mmapbuf + meta_offset + size);
- if (len > 0) {
- _codec_decode_audio_outbuf (*have_data, samples, mmapbuf + mem_offset);
- }
- memset(mmapbuf + mem_offset, 0x00, sizeof(len));
-
- ret = ioctl(fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed release used memory\n");
- }
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-
- return len;
-}
-
-int
-codec_encode_video (CodecContext *ctx, uint8_t *out_buf,
- int out_size, uint8_t *in_buf,
- int in_size, int64_t in_timestamp, CodecDevice *dev)
-{
- int fd, len = 0;
- int ret, size;
- uint8_t *mmapbuf = NULL;
- uint32_t mem_offset = 0, meta_offset = 0;
-
- CODEC_LOG (DEBUG, "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;
- }
-
- if (in_size < SMALL_BUFFER) {
- CODEC_LOG (DEBUG, "use small size of buffer\n");
-
- ret = ioctl (fd, CODEC_CMD_S_SECURE_BUFFER, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed to small size of buffer.\n");
- return -1;
- }
- } else if (in_size < MEDIUM_BUFFER) {
- CODEC_LOG (DEBUG, "use medium size of buffer\n");
-
- ret = ioctl (fd, CODEC_CMD_M_SECURE_BUFFER, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed to small size of buffer.\n");
- return -1;
- }
- } else {
- CODEC_LOG (DEBUG, "use large size of buffer\n");
- ret = ioctl (fd, CODEC_CMD_L_SECURE_BUFFER, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed to large size of buffer.\n");
- return -1;
- }
- }
- CODEC_LOG (DEBUG, "encode_video. mem_offset = 0x%x\n", mem_offset);
-
- meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
- CODEC_LOG (DEBUG, "encode_video. meta_offset = 0x%x\n", meta_offset);
-
-// size =
-// _codec_header (CODEC_ENCODE_VIDEO, mem_offset, mmapbuf + meta_offset);
- size = 8;
- meta_offset += size;
- _codec_encode_video_meta_to (in_size, in_timestamp, mmapbuf + meta_offset);
- _codec_encode_video_inbuf (in_buf, in_size, mmapbuf + mem_offset);
-
- dev->mem_info.offset = mem_offset;
- _codec_write_to_qemu (ctx->index, CODEC_ENCODE_VIDEO, mem_offset, fd);
-
-#ifndef DIRECT_BUFFER
- ret = ioctl (fd, CODEC_CMD_REQ_FROM_SMALL_MEMORY, &mem_offset);
- if (ret < 0) {
- return -1;
- }
- CODEC_LOG (DEBUG, "read, encode_video. mem_offset = 0x%x\n", mem_offset);
-
- memcpy (&len, mmapbuf + meta_offset, sizeof(len));
- CODEC_LOG (DEBUG, "encode_video. outbuf size: %d\n", len);
- if (len > 0) {
- memcpy (out_buf, mmapbuf + mem_offset, len);
- out_buf = mmapbuf + mem_offset;
- }
-
- dev->mem_info.offset = mem_offset;
-#if 0
- len =
- _codec_encode_video_outbuf (out_buf, mmapbuf + mem_offset);
-// memset(mmapbuf + mem_offset, 0x00, sizeof(len));
-#endif
-
-#if 1
- ret = ioctl(fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed release used memory\n");
- }
-#endif
-#else
- dev->mem_info.offset = (uint32_t)pict - (uint32_t)mmapbuf;
- CODEC_LOG (DEBUG, "outbuf: %p , device_mem: %p\n", pict, mmapbuf);
- CODEC_LOG (DEBUG, "encoded video. mem_offset = 0x%x\n", dev->mem_info.offset);
-
- ret = ioctl (fd, CODEC_CMD_USE_DEVICE_MEM, &(dev->mem_info.offset));
- if (ret < 0) {
- // FIXME:
- }
-#endif
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-
- return len;
-}
-
-int
-codec_encode_audio (CodecContext *ctx, uint8_t *out_buf,
- int max_size, uint8_t *in_buf,
- int in_size, CodecDevice *dev)
-{
- int fd, len = 0;
- int ret, size;
- void *mmapbuf = NULL;
- uint32_t mem_offset = 0, meta_offset = 0;
-
- CODEC_LOG (DEBUG, "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;
- }
-
- ret = ioctl (fd, CODEC_CMD_S_SECURE_BUFFER, &mem_offset);
- if (ret < 0) {
- return -1;
- }
-
- CODEC_LOG (DEBUG, "write, encode_audio. mem_offset = 0x%x\n", mem_offset);
-
- meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
- CODEC_LOG (DEBUG, "encode_audio. meta mem_offset = 0x%x\n", meta_offset);
-
- size = _codec_header (CODEC_ENCODE_AUDIO, mem_offset,
- mmapbuf + meta_offset);
- _codec_encode_audio_meta_to (max_size, in_size, mmapbuf + meta_offset + size);
- _codec_encode_audio_inbuf (in_buf, in_size, mmapbuf + mem_offset);
-
- dev->mem_info.offset = mem_offset;
- _codec_write_to_qemu (ctx->index, CODEC_ENCODE_AUDIO, mem_offset, fd);
-
- ret = ioctl (fd, CODEC_CMD_REQ_FROM_SMALL_MEMORY, &mem_offset);
- if (ret < 0) {
- return -1;
- }
-
- CODEC_LOG (DEBUG, "read, encode_video. mem_offset = 0x%x\n", mem_offset);
-
- len = _codec_encode_audio_outbuf (out_buf, mmapbuf + mem_offset);
- memset(mmapbuf + mem_offset, 0x00, sizeof(len));
-
- ret = ioctl(fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
- if (ret < 0) {
- return -1;
- }
-
- CODEC_LOG (DEBUG, "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"
-
-int
-codec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev);
-
-void
-codec_deinit (CodecContext *ctx, CodecDevice *dev);
-
-int
-codec_decode_video (CodecContext *ctx, uint8_t *in_buf, int in_size,
- gint idx, gint64 in_offset, GstBuffer **out_buf,
- int *got_picture_ptr, CodecDevice *dev);
-
-
-int
-codec_decode_audio (CodecContext *ctx, int16_t *samples,
- int *frame_size_ptr, uint8_t *in_buf,
- int in_size, CodecDevice *dev);
-
-int
-codec_encode_video (CodecContext *ctx, uint8_t*out_buf,
- int out_size, uint8_t *in_buf,
- int in_size, int64_t in_timestamp,
- CodecDevice *dev);
-
-int
-codec_encode_audio (CodecContext *ctx, uint8_t *out_buf,
- int out_size, uint8_t *in_buf,
- int in_size, CodecDevice *dev);
-
-void
-codec_picture_copy (CodecContext *ctx, uint8_t *pict,
- uint32_t pict_size, CodecDevice *dev);
-
-GstFlowReturn
-codec_buffer_alloc (GstPad *pad, guint64 offset,
- guint size, GstCaps *caps, GstBuffer **buf);
-
-#endif /* __GST_EMUL_API_H__ */
+++ /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 "gstemulapi2.h"
-
-/*
- * codec data such as codec name, longname, media type and etc.
- */
-static int
-_codec_info_data (CodecElement *codec, uint8_t *device_buf)
-{
- int size = 0;
-
- CODEC_LOG (DEBUG, "enter, %s\n", __func__);
-
- CODEC_LOG (DEBUG, "type: %d, name: %s\n", codec->codec_type, codec->name);
- memcpy (device_buf, &codec->codec_type, sizeof(codec->codec_type));
- size = sizeof(codec->codec_type);
-
- memcpy (device_buf + size, codec->name, sizeof(codec->name));
- size += sizeof(codec->name);
-
- CODEC_LOG (DEBUG, "leave, %s\n", __func__);
-
- return size;
-}
-
-void
-_codec_init_meta_to (CodecContext *ctx,
- CodecElement *codec,
- uint8_t *device_buf)
-{
- int size = 0;
-
- CODEC_LOG (DEBUG, "enter, %s\n", __func__);
-
- size = _codec_info_data (codec, device_buf);
-
- if (codec->media_type == AVMEDIA_TYPE_AUDIO) {
- CODEC_LOG (INFO,
- "before init. audio sample_fmt: %d\n", ctx->audio.sample_fmt);
- }
-
- CODEC_LOG (DEBUG, "init. write data to qemu, size: %d\n", size);
- memcpy (device_buf + size, ctx, sizeof(CodecContext) - 12);
- size += (sizeof(CodecContext) - 12);
- memcpy (device_buf + size, ctx->codecdata, ctx->codecdata_size);
-
- CODEC_LOG (DEBUG, "leave, %s\n", __func__);
-}
-
-int
-_codec_init_meta_from (CodecContext *ctx,
- int media_type,
- uint8_t *device_buf)
-{
- int ret = 0, size = 0;
-
- CODEC_LOG (DEBUG, "after init. read data from device.\n");
-
- memcpy (&ret, device_buf, sizeof(ret));
- size = sizeof(ret);
- if (!ret) {
- if (media_type == AVMEDIA_TYPE_AUDIO) {
- AudioData audio = { 0 };
-
-#if 0
- memcpy(&audio, device_buf + size, sizeof(AudioData));
- ctx->audio.sample_fmt = audio.sample_fmt;
- ctx->audio.frame_size = audio.frame_size;
- ctx->audio.bits_per_sample_fmt = audio.bits_per_sample_fmt;
-#endif
- CODEC_LOG (INFO,
- "audio sample_fmt: %d\n", *(int *)(device_buf + size));
-
- memcpy(&ctx->audio.sample_fmt, device_buf + size, sizeof(audio.sample_fmt));
- size += sizeof(audio.sample_fmt);
- memcpy(&ctx->audio.frame_size, device_buf + size, sizeof(audio.frame_size));
- size += sizeof(audio.frame_size);
- memcpy(&ctx->audio.bits_per_sample_fmt, device_buf + size, sizeof(audio.bits_per_sample_fmt));
-
- CODEC_LOG (INFO,
- "after init. audio sample_fmt: %d\n", ctx->audio.sample_fmt);
- }
- } else {
- CODEC_LOG (ERR, "failed to open codec context\n");
- }
-
- return ret;
-}
-
-void
-_codec_decode_video_meta_to (int in_size, int idx, int64_t in_offset, uint8_t *device_buf)
-{
- memcpy (device_buf, &in_size, sizeof(in_size));
- memcpy (device_buf + sizeof(in_size), &idx, sizeof(idx));
- memcpy (device_buf + sizeof(idx), &in_offset, sizeof(in_offset));
-}
-
-void
-_codec_decode_video_inbuf (uint8_t *in_buf, int in_size,
- uint8_t *device_buf)
-{
- int size = 0;
-
- memcpy(device_buf, &in_size, sizeof(in_size));
- size = sizeof(in_size);
- if (in_size > 0 ) {
- memcpy (device_buf + size, in_buf, in_size);
- }
-
- CODEC_LOG (DEBUG, "decode_video. inbuf_size: %d\n", in_size);
-}
-
-
-int
-_codec_decode_video_meta_from (VideoData *video,
- int *got_picture_ptr,
- uint8_t *device_buf)
-{
- int len = 0, size = 0;
-
- CODEC_LOG (DEBUG, "decode_video. read data from qemu.\n");
-
- memcpy (&len, device_buf, sizeof(len));
- size = sizeof(len);
- memcpy (got_picture_ptr,
- device_buf + size, sizeof(*got_picture_ptr));
- size += sizeof(*got_picture_ptr);
- memcpy (video, device_buf + size, sizeof(VideoData));
-
- CODEC_LOG (DEBUG, "decode_video. len: %d, have_data: %d\n",
- len, *got_picture_ptr);
-
- return len;
-}
-
-void
-_codec_decode_audio_meta_to (int in_size, uint8_t *device_buf)
-{
- memcpy (device_buf, &in_size, sizeof(in_size));
-}
-
-
-void
-_codec_decode_audio_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf)
-{
- int size = 0;
-
- memcpy (device_buf, &in_size, sizeof(in_size));
- size = sizeof(in_size);
- if (in_size > 0) {
- memcpy (device_buf + size, in_buf, in_size);
- }
-
- CODEC_LOG (DEBUG, "decode_audio. inbuf_size: %d\n", in_size);
-}
-
-int
-_codec_decode_audio_meta_from (AudioData *audio, int *frame_size_ptr,
- uint8_t *device_buf)
-{
- int len = 0, size = 0;
-
- CODEC_LOG (DEBUG, "decode_audio. read data from device.\n");
-
- memcpy (&audio->channel_layout,
- device_buf, sizeof(audio->channel_layout));
- size = sizeof(audio->channel_layout);
- memcpy (&len, device_buf + size, sizeof(len));
- size += sizeof(len);
- memcpy (frame_size_ptr, device_buf + size, sizeof(*frame_size_ptr));
-
- CODEC_LOG (DEBUG, "decode_audio. len: %d, frame_size: %d\n",
- len, (*frame_size_ptr));
-
- return len;
-}
-
-void
-_codec_decode_audio_outbuf (int outbuf_size, int16_t *samples, uint8_t *device_buf)
-{
- CODEC_LOG (DEBUG, "decode_audio. read outbuf %d\n", outbuf_size);
- memcpy (samples, device_buf, outbuf_size);
-}
-
-void
-_codec_encode_video_meta_to (int in_size, int64_t in_timestamp, uint8_t *device_buf)
-{
- CODEC_LOG (DEBUG, "encode_video. write data to device.\n");
-
- memcpy (device_buf, &in_size, sizeof(in_size));
- memcpy (device_buf + sizeof(in_size), &in_timestamp, sizeof(in_timestamp));
-}
-
-void
-_codec_encode_video_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf)
-{
- int size = 0;
-
- memcpy ((uint8_t *)device_buf, &in_size, sizeof(in_size));
- size += sizeof(in_size);
- if (in_size > 0) {
- memcpy (device_buf + size, in_buf, in_size);
- }
- CODEC_LOG (DEBUG, "encode_video. inbuf_size: %d\n", in_size);
-}
-
-void
-_codec_encode_video_outbuf (int len, uint8_t *out_buf, uint8_t *device_buf)
-{
-// int len, size;
-
- CODEC_LOG (DEBUG, "encode_video. read data from device.\n");
-
-// memcpy (&len, device_buf, sizeof(len));
-// size = sizeof(len);
- memcpy (out_buf, device_buf, len);
-
-// return len;
-}
-
-void
-_codec_encode_audio_meta_to (int max_size, int in_size, uint8_t *device_buf)
-{
- int size = 0;
-
- CODEC_LOG (DEBUG, "encode_audio. write data to device.\n");
-
- memcpy (device_buf, &in_size, sizeof(in_size));
- size = sizeof(in_size);
- memcpy (device_buf + size, &max_size, sizeof(max_size));
-}
-
-void
-_codec_encode_audio_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf)
-{
- int size = 0;
-
- memcpy (device_buf, &in_size, sizeof(in_size));
- size = sizeof(in_size);
- if (in_size > 0) {
- memcpy (device_buf + size, in_buf, in_size);
- }
- CODEC_LOG (DEBUG, "encode_audio. inbuf_size: %d\n", in_size);
-}
-
-int
-_codec_encode_audio_outbuf (uint8_t *out_buf, uint8_t *device_buf)
-{
- int len, size;
-
- CODEC_LOG (DEBUG, "encode_audio. read data from device\n");
-
- memcpy (&len, (uint8_t *)device_buf, sizeof(len));
- size = sizeof(len);
- memcpy (out_buf, (uint8_t *)device_buf + size, len);
-
- 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
- *
- */
-
-#include "gstemulcommon.h"
-
-void _codec_init_meta_to (CodecContext *ctx, CodecElement *codec, uint8_t *device_buf);
-
-int _codec_init_meta_from (CodecContext *ctx, int media_type, uint8_t *device_buf);
-
-void _codec_decode_video_meta_to (int in_size, int idx, int64_t in_offset, uint8_t *device_buf);
-
-void _codec_decode_video_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf);
-
-int _codec_decode_video_meta_from (VideoData *video, int *got_picture_ptr,
- uint8_t *device_buf);
-
-void _codec_decode_audio_meta_to (int in_size, uint8_t *device_buf);
-
-
-void _codec_decode_audio_inbuf (uint8_t *in_buf, int in_size,
- uint8_t *device_buf);
-
-int _codec_decode_audio_meta_from (AudioData *audio, int *frame_size_ptr,
- uint8_t *device_buf);
-
-void _codec_decode_audio_outbuf (int outbuf_size, int16_t *samples,
- uint8_t *device_buf);
-
-void _codec_encode_video_meta_to (int in_size, int64_t in_timestamp, uint8_t *device_buf);
-
-void _codec_encode_video_inbuf (uint8_t *in_buf, int in_size,
- uint8_t *device_buf);
-
-// int _codec_encode_video_outbuf (uint8_t *out_buf, uint8_t *device_buf);
-void _codec_encode_video_outbuf (int len, uint8_t *outbuf, uint8_t *device_buf);
-
-void _codec_encode_audio_meta_to (int max_size, int in_size, uint8_t *device_buf);
-
-void _codec_encode_audio_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf);
-
-int _codec_encode_audio_outbuf (uint8_t *out_buf, uint8_t *device_buf);
+++ /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_H__
-#define __GST_EMUL_H__
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-// #include <semaphore.h>
-#include <glib.h>
-#include <gst/gst.h>
-#include "pixfmt.h"
-
-GST_DEBUG_CATEGORY_EXTERN (emul_debug);
-#define GST_CAT_DEFAULT emul_debug
-
-G_BEGIN_DECLS
-
-enum codec_log_level {
- ERR,
- WARN,
- INFO,
- DEBUG,
-};
-
-#define CODEC_DEV "/dev/newcodec"
-#define CODEC_VER 1
-
-#define CODEC_LOG(level, fmt, ...) \
- do { \
- if (level <= INFO) \
- printf("[gst-emul][%d] " fmt, __LINE__, ##__VA_ARGS__); \
- } while (0)
-
-#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
-
-#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))
-
-typedef struct _CodecIOParams {
- int32_t api_index;
- int32_t ctx_index;
- uint32_t mem_offset;
-} CodecIOParams;
-
-typedef struct _CodecDeviceMem {
- uint32_t index;
- uint32_t offset;
-} CodecDeviceMem;
-
-typedef struct _CodecDevice {
- int fd;
- uint8_t *buf;
- uint32_t buf_size;
- CodecDeviceMem mem_info;
-} CodecDevice;
-
-typedef struct _CodecElement {
- int32_t codec_type;
- int32_t media_type;
- gchar name[32];
- gchar longname[64];
- union {
- int32_t pix_fmts[4];
- int32_t sample_fmts[4];
- };
-} CodecElement;
-
-typedef struct _VideoData {
- int32_t width, height;
- int32_t fps_n, fps_d;
- int32_t par_n, par_d;
- int32_t pix_fmt, bpp;
- int32_t ticks_per_frame;
-} VideoData;
-
-typedef struct _AudioData {
- int32_t channels, sample_rate;
- int32_t block_align, depth;
- int32_t sample_fmt, frame_size;
- int32_t bits_per_sample_fmt;
- int64_t channel_layout;
-} AudioData;
-
-typedef struct _CodecContext {
- union {
- VideoData video;
- AudioData audio;
- };
-
- int32_t bit_rate;
- int32_t codec_tag;
-
- int32_t codecdata_size;
- uint8_t *codecdata;
-
- CodecElement *codec;
- int32_t index;
-} CodecContext;
-
-enum CODEC_FUNC_TYPE {
- CODEC_INIT = 0,
- CODEC_DECODE_VIDEO,
- CODEC_ENCODE_VIDEO,
- CODEC_DECODE_AUDIO,
- CODEC_ENCODE_AUDIO,
- CODEC_PICTURE_COPY,
- CODEC_DEINIT,
-};
-
-enum CODEC_IO_CMD {
- CODEC_CMD_COPY_TO_DEVICE_MEM = 5,
- CODEC_CMD_COPY_FROM_DEVICE_MEM,
- CODEC_CMD_GET_VERSION = 20,
- CODEC_CMD_GET_ELEMENT,
- CODEC_CMD_GET_CONTEXT_INDEX,
- CODEC_CMD_SECURE_MEMORY = 30,
- CODEC_CMD_RELEASE_MEMORY,
- CODEC_CMD_USE_DEVICE_MEM,
- CODEC_CMD_REQ_FROM_SMALL_MEMORY,
- CODEC_CMD_REQ_FROM_MEDIUM_MEMORY,
- CODEC_CMD_REQ_FROM_LARGE_MEMORY,
- CODEC_CMD_S_SECURE_BUFFER,
- CODEC_CMD_M_SECURE_BUFFER,
- CODEC_CMD_L_SECURE_BUFFER,
-};
-
-
-#define CODEC_META_DATA_SIZE 256
-
-// CODEC_CMD_REQ_TO_SMALL_MEMORY
-// CODEC_CMD_REQ_FROM_SMALL_MEMORY
-// CODEC_CMD_REQ_TO_LARGE_MEMORY
-// CODEC_CMD_REQ_FROM_LARGE_MEMORY
-
-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,
- SAMPLE_FMT_S16,
- SAMPLE_FMT_S32,
- SAMPLE_FMT_FLT,
- SAMPLE_FMT_DBL,
- SAMPLE_FMT_NB
-};
-
-/* Define codec types.
- * e.g. FFmpeg, x264, libvpx and etc.
- */
-enum {
- FFMPEG_TYPE = 1,
-};
-
-G_END_DECLS
-#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"
-#include "gstemuldev.h"
-
-#define GST_EMULDEC_PARAMS_QDATA g_quark_from_static_string("marudec-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 opened;
- 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, gint64 in_offset, GstFlowReturn *ret);
-
-static gboolean gst_emuldec_open (GstEmulDec *emuldec);
-static int 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;
- }
- }
-
- emuldec->processed++;
- return TRUE;
-}
-
-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;
-
- CODEC_LOG (DEBUG, "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, 0, &ret);
-
- if (len < 0 || have_data == 0) {
- break;
- }
- } while (try++ < 10);
- }
-#endif
-
- if (emuldec->segment.rate < 0.0) {
- CODEC_LOG (DEBUG, "reverse playback\n");
- flush_queued (emuldec);
- }
-}
-
-/*
- * Implementation
- */
-static void
-gst_emuldec_base_init (GstEmulDecClass *klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- GstCaps *sinkcaps = NULL, *srccaps = NULL;
- GstPadTemplate *sinktempl, *srctempl;
- CodecElement *codec;
- gchar *longname, *classification, *description;
-
- 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");
- description = g_strdup_printf("%s Decoder", codec->name);
-
- gst_element_class_set_details_simple (element_class,
- longname,
- classification,
- description,
- "Kitae Kim <kt920.kim@samsung.com>");
-
- g_free (longname);
- g_free (classification);
- g_free (description);
-
- 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);
-
- emuldec->context = g_malloc0 (sizeof(CodecContext));
- emuldec->context->video.pix_fmt = PIX_FMT_NONE;
- emuldec->context->audio.sample_fmt = SAMPLE_FMT_NONE;
-
- emuldec->opened = FALSE;
- 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);
-
- emuldec->dev = g_malloc0 (sizeof(CodecDevice));
- if (!emuldec->dev) {
- CODEC_LOG (ERR, "failed to allocate memory.\n");
- }
-}
-
-static void
-gst_emuldec_finalize (GObject *object)
-{
- GstEmulDec *emuldec = (GstEmulDec *) object;
-
- if (emuldec->context) {
- 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;
-
- gst_event_parse_qos (event, &proportion, &diff, ×tamp);
-
- /* update our QoS values */
- gst_emuldec_update_qos (emuldec, proportion, timestamp + diff);
- break;
- }
- default:
- break;
- }
-
- /* forward upstream */
- res = gst_pad_push_event (emuldec->sinkpad, event);
-
- gst_object_unref (emuldec);
-
- return res;
-}
-
-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:
- gst_emuldec_drain (emuldec);
- break;
- case GST_EVENT_FLUSH_STOP:
- {
- printf("[%s][%d] GST_EVET_FLUSH_STOP\n", __func__, __LINE__);
-#if 0
- if (emuldec->opened) {
- // TODO: what does avcodec_flush_buffers do?
- emul_avcodec_flush_buffers (emuldec->context, emuldec->dev);
- }
-#endif
- gst_emuldec_reset_ts (emuldec);
- gst_emuldec_reset_qos (emuldec);
-#if 0
- gst_emuldec_flush_pcache (emuldec);
- emuldec->waiting_for_key = TRUE;
-#endif
- gst_segment_init (&emuldec->segment, GST_FORMAT_TIME);
- clear_queued (emuldec);
- }
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- gboolean update;
- GstFormat format;
- gint64 start, stop, time;
- gdouble rate, arate;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- switch (format) {
- case GST_FORMAT_TIME:
- break;
- case GST_FORMAT_BYTES:
- {
- gint bit_rate;
- bit_rate = emuldec->context->bit_rate;
-
- if (!bit_rate) {
- 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:
- GST_WARNING_OBJECT (emuldec, "unknown format received in NEWSEGMENT");
- gst_event_unref (event);
- gst_object_unref (emuldec);
- return ret;
- }
-
- if (emuldec->context->codec) {
- gst_emuldec_drain (emuldec);
- }
-
- GST_DEBUG_OBJECT (emuldec,
- "NEWSEGMENT in time start %" GST_TIME_FORMAT " -- stop %"
- GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
-
- 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 (emuldec->opened) {
- GST_OBJECT_UNLOCK (emuldec);
- gst_emuldec_drain (emuldec);
- GST_OBJECT_LOCK (emuldec);
- gst_emuldec_close (emuldec);
- }
-
- 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 0
- if (strcmp (oclass->codec->name, "aac") == 0) {
- const gchar *format = gst_structure_get_string (structure, "stream-format");
- 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 gboolean
-gst_emuldec_open (GstEmulDec *emuldec)
-{
- GstEmulDecClass *oclass;
-
- oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
-
- if (!emuldec->dev) {
- return FALSE;
- }
-
- if (gst_emul_avcodec_open (emuldec->context,
- oclass->codec, emuldec->dev) < 0) {
- gst_emuldec_close (emuldec);
- GST_ERROR_OBJECT (emuldec,
- "maru_%sdec: Failed to open codec", oclass->codec->name);
- return FALSE;
- }
-
- emuldec->opened = TRUE;
- 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 int
-gst_emuldec_close (GstEmulDec *emuldec)
-{
- int ret = 0;
-
- if (emuldec->context->codecdata) {
- g_free(emuldec->context->codecdata);
- emuldec->context->codecdata = NULL;
- }
-
- if (!emuldec->dev) {
- return -1;
- }
-
- ret = gst_emul_avcodec_close (emuldec->context, emuldec->dev);
-
- if (emuldec->dev) {
- g_free(emuldec->dev);
- emuldec->dev = NULL;
- }
-
- return ret;
-}
-
-
-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:
- break;
- 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 GstFlowReturn
-get_output_buffer (GstEmulDec *emuldec, GstBuffer **outbuf)
-{
- gint pict_size;
- GstFlowReturn ret;
-
- ret = GST_FLOW_OK;
-
- *outbuf = NULL;
-
- if (G_UNLIKELY (!gst_emuldec_negotiate (emuldec, FALSE))) {
- GST_DEBUG_OBJECT (emuldec, "negotiate failed");
- return GST_FLOW_NOT_NEGOTIATED;
- }
-
- pict_size = gst_emul_avpicture_size (emuldec->context->video.pix_fmt,
- emuldec->context->video.width, emuldec->context->video.height);
- if (pict_size < 0) {
- GST_DEBUG_OBJECT (emuldec, "size of a picture is negative. "
- "pixel format: %d, width: %d, height: %d",
- emuldec->context->video.pix_fmt, emuldec->context->video.width,
- emuldec->context->video.height);
- return GST_FLOW_ERROR;
- }
-
- CODEC_LOG (DEBUG, "outbuf size of decoded video: %d\n", pict_size);
-
- if (pict_size < (256 * 1024)) {
- /* GstPadBufferAllocFunction is mostly overridden by elements that can
- * provide a hardware buffer in order to avoid additional memcpy operations.
- */
- gst_pad_set_bufferalloc_function(
- GST_PAD_PEER(emuldec->srcpad),
- (GstPadBufferAllocFunction) codec_buffer_alloc);
- } else {
- CODEC_LOG (DEBUG, "request a large size of memory\n");
- }
-
- ret = gst_pad_alloc_buffer_and_set_caps (emuldec->srcpad,
- GST_BUFFER_OFFSET_NONE, pict_size,
- GST_PAD_CAPS (emuldec->srcpad), outbuf);
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- GST_DEBUG_OBJECT (emuldec, "pad_alloc failed %d (%s)", ret,
- gst_flow_get_name (ret));
- return ret;
- }
-
- if ((uintptr_t) GST_BUFFER_DATA (*outbuf) % 16) {
- GST_DEBUG_OBJECT (emuldec,
- "Downstream can't allocate aligned buffers.");
- gst_buffer_unref (*outbuf);
- *outbuf = new_aligned_buffer (pict_size, GST_PAD_CAPS (emuldec->srcpad));
- }
-
- codec_picture_copy (emuldec->context, GST_BUFFER_DATA (*outbuf),
- GST_BUFFER_SIZE (*outbuf), emuldec->dev);
-
- return ret;
-}
-
-static gboolean
-clip_video_buffer (GstEmulDec *dec, GstBuffer *buf,
- GstClockTime in_ts, GstClockTime in_dur)
-{
- gboolean res = TRUE;
-
- return res;
-}
-
-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, gint64 in_offset, GstBuffer **outbuf,
- GstFlowReturn *ret)
-{
- gint len = -1, have_data;
- gboolean mode_switch;
- gboolean decode;
- GstClockTime out_timestamp, out_duration, out_pts;
- gint64 out_offset;
- const GstTSInfo *out_info;
-
- decode = gst_emuldec_do_qos (emuldec, dec_info->timestamp, &mode_switch);
-
- CODEC_LOG (DEBUG, "decode video: input buffer size: %d\n", size);
- len =
- codec_decode_video (emuldec->context, data, size,
- dec_info->idx, in_offset, outbuf,
- &have_data, emuldec->dev);
-
- if (!decode) {
- // skip_frame
- }
-
- GST_DEBUG_OBJECT (emuldec, "after decode: len %d, have_data %d",
- len, have_data);
-
-#if 0
- if (len < 0 && (mode_switch || emuldec->context->skip_frame)) {
- len = 0;
- }
-
- if (len > 0 && have_data <= 0 && (mode_switch
- || emuldec->context->skip_frame)) {
- emuldec->last_out = -1;
- }
-#endif
-
- if (len < 0 || have_data <= 0) {
- GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
- *ret, *outbuf, len);
- return len;
- }
-
- out_info = gst_ts_info_get (emuldec, dec_info->idx);
- out_pts = out_info->timestamp;
- out_duration = out_info->duration;
- out_offset = out_info->offset;
-
- *ret = get_output_buffer (emuldec, outbuf);
- if (G_UNLIKELY (*ret != GST_FLOW_OK)) {
- GST_DEBUG_OBJECT (emuldec, "no output buffer");
- len = -1;
- GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
- *ret, *outbuf, len);
- return len;
- }
-
- /* Timestamps */
- out_timestamp = -1;
- if (out_pts != -1) {
- out_timestamp = (GstClockTime) out_pts;
- GST_LOG_OBJECT (emuldec, "using timestamp %" GST_TIME_FORMAT
- " returned by ffmpeg", GST_TIME_ARGS (out_timestamp));
- }
-
- if (!GST_CLOCK_TIME_IS_VALID (out_timestamp) && emuldec->next_out != -1) {
- out_timestamp = emuldec->next_out;
- GST_LOG_OBJECT (emuldec, "using next timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (out_timestamp));
- }
-
- if (!GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
- out_timestamp = dec_info->timestamp;
- GST_LOG_OBJECT (emuldec, "using in timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (out_timestamp));
- }
- GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp;
-
- /* Offset */
- if (out_offset != GST_BUFFER_OFFSET_NONE) {
- GST_LOG_OBJECT (emuldec, "Using offset returned by ffmpeg");
- } else if (out_timestamp != GST_CLOCK_TIME_NONE) {
- GstFormat out_fmt = GST_FORMAT_DEFAULT;
- GST_LOG_OBJECT (emuldec, "Using offset converted from timestamp");
-
- gst_pad_query_peer_convert (emuldec->sinkpad,
- GST_FORMAT_TIME, out_timestamp, &out_fmt, &out_offset);
- } else if (dec_info->offset != GST_BUFFER_OFFSET_NONE) {
- GST_LOG_OBJECT (emuldec, "using in_offset %" G_GINT64_FORMAT,
- dec_info->offset);
- out_offset = dec_info->offset;
- } else {
- GST_LOG_OBJECT (emuldec, "no valid offset found");
- out_offset = GST_BUFFER_OFFSET_NONE;
- }
- GST_BUFFER_OFFSET (*outbuf) = out_offset;
-
- /* Duration */
- if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
- GST_LOG_OBJECT (emuldec, "Using duration returned by ffmpeg");
- } else if (GST_CLOCK_TIME_IS_VALID (dec_info->duration)) {
- GST_LOG_OBJECT (emuldec, "Using in_duration");
- out_duration = dec_info->duration;
-#if 0
- } else if (GST_CLOCK_TIME_IS_VALID (emuldec->last_diff)) {
- GST_LOG_OBJECT (emuldec, "Using last-diff");
- out_duration = emuldec->last_diff;
-#endif
- } else {
- if (emuldec->format.video.fps_n != -1 &&
- (emuldec->format.video.fps_n != 1000 &&
- emuldec->format.video.fps_d != 1)) {
- GST_LOG_OBJECT (emuldec, "using input framerate for duration");
- out_duration = gst_util_uint64_scale_int (GST_SECOND,
- emuldec->format.video.fps_d, emuldec->format.video.fps_n);
- } else {
- if (emuldec->context->video.fps_n != 0 &&
- (emuldec->context->video.fps_d > 0 &&
- emuldec->context->video.fps_d < 1000)) {
- GST_LOG_OBJECT (emuldec, "using decoder's framerate for duration");
- out_duration = gst_util_uint64_scale_int (GST_SECOND,
- emuldec->context->video.fps_n * 1,
- emuldec->context->video.fps_d);
- } else {
- GST_LOG_OBJECT (emuldec, "no valid duration found");
- }
- }
- }
-
-#if 0
- if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
- out_duration += out_duration * emuldec->picture->repeat_pict / 2;
- }
- GST_BUFFER_DURATION (*outbuf) = out_duration;
-
- if (out_timestamp != -1 && out_duration != -1 && out_duration != 0) {
- emuldec->next_out = out_timestamp + out_duration;
- } else {
- emuldec->next_out = -1;
- }
-#endif
-
- if (G_UNLIKELY (!clip_video_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;
- }
-
- GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
- *ret, *outbuf, len);
- 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));
-
- CODEC_LOG (DEBUG, "decode audio, input buffer size: %d\n", size);
-
- len = codec_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);
-
-// CODEC_LOG (INFO, "decode audio, sample_fmt: %d\n", emuldec->context->audio.sample_fmt);
-
- 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;
- }
-
- /* calculate based on number of samples */
- 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 FFMPEG 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, gint64 in_offset, GstFlowReturn *ret)
-{
- GstEmulDecClass *oclass;
- GstBuffer *outbuf = NULL;
- gint have_data = 0, len = 0;
-
- if (G_UNLIKELY (emuldec->context->codec == NULL)) {
- 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, in_offset, &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,
- "maru_%sdec: 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
- GST_DEBUG_OBJECT (emuldec, "queued frame");
- 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;
- gint 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 (G_UNLIKELY (!emuldec->opened)) {
- // not_negotiated
- oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
- GST_ELEMENT_ERROR (emuldec, CORE, NEGOTIATION, (NULL),
- ("maru_%sdec: input format was not set before data start",
- oclass->codec->name));
- gst_buffer_unref (buffer);
- return GST_FLOW_NOT_NEGOTIATED;
- }
-
- discont = GST_BUFFER_IS_DISCONT (buffer);
-
-// FIXME
- if (G_UNLIKELY (discont)) {
- GST_DEBUG_OBJECT (emuldec, "received DISCONT");
- gst_emuldec_drain (emuldec);
-// gst_emuldec_flush_pcache (emuldec);
-// emul_avcodec_flush buffers (emuldec->context, emuldec->dev);
- 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
-
- GST_LOG_OBJECT (emuldec,
- "Received new data of size %u, offset: %" G_GUINT64_FORMAT ", ts:%"
- GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT ", info %d",
- GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer),
- GST_TIME_ARGS (in_timestamp), GST_TIME_ARGS (in_duration), in_info->idx);
-
- 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, in_offset, &ret);
-
-#if 0
- if (emuldec->clear_ts) {
- in_timestamp = GST_CLOCK_TIME_NONE;
- in_duration = GST_CLOCK_TIME_NONE;
- in_offset = GST_BUFFER_OFFSET_NONE;
- in_info = GST_TS_INFO_NONE;
- } else {
- emuldec->clear_ts = TRUE;
- }
-#endif
-
- 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_NONE;
- GList *elem = element;
- CodecElement *codec = NULL;
-
- if (!elem) {
- return FALSE;
- }
-
- /* register element */
- do {
- codec = (CodecElement *)(elem->data);
- if (!codec) {
- return FALSE;
- }
-
- if (codec->codec_type != CODEC_TYPE_DECODE) {
- continue;
- }
-
- type_name = g_strdup_printf ("maru_%sdec", 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);
- } while ((elem = elem->next));
-
- return TRUE;
-}
+++ /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 <fcntl.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include "gstemulapi.h"
-#include "gstemuldev.h"
-
-static GStaticMutex gst_avcodec_mutex = G_STATIC_MUTEX_INIT;
-
-#define CODEC_DEVICE_MEM_SIZE 32 * 1024 * 1024
-
-gpointer device_mem;
-int device_fd;
-
-int
-gst_emul_codec_device_open (CodecDevice *dev, int media_type)
-{
- int fd;
- void *mmapbuf;
-
- CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-
- CODEC_LOG (INFO, "before opening a device. %d\n", dev->fd);
- if ((fd = open(CODEC_DEV, O_RDWR)) < 0) {
- perror("Failed to open codec device.");
- return -1;
- }
- dev->fd = fd;
-
-// GST_DEBUG("succeeded to open %s. %d.\n", CODEC_DEV, fd);
- CODEC_LOG (INFO, "succeeded to open %s. %d.\n", CODEC_DEV, fd);
- dev->mem_info.index = dev->buf_size;
-
- CODEC_LOG (DEBUG, "before mmap. buf_size: %d\n", dev->buf_size);
- mmapbuf = mmap (NULL, CODEC_DEVICE_MEM_SIZE, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (mmapbuf == MAP_FAILED) {
- perror("Failed to map device memory of codec.");
- dev->buf = NULL;
- return -1;
- }
-
-// GST_DEBUG("succeeded to map device memory.\n");
- CODEC_LOG (INFO, "succeeded to map device memory: %p.\n", mmapbuf);
- dev->fd = fd;
- dev->buf = mmapbuf;
-
- if (media_type == AVMEDIA_TYPE_VIDEO) {
- device_mem = mmapbuf;
- device_fd = fd;
- CODEC_LOG (INFO, "video type! mmapbuf: %p fd: %d\n", mmapbuf, fd);
- }
-#if 0
- else {
- CODEC_LOG (INFO, "don't need to set device_mem because media type is not video. %d\n", media_type);
- }
-#endif
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-
- return 0;
-}
-
-int
-gst_emul_codec_device_close (CodecDevice *dev)
-{
- int fd = 0;
- void *mmapbuf = NULL;
-
- CODEC_LOG (DEBUG, "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;
- }
-
- CODEC_LOG (INFO, "Release memory region of %p.\n", mmapbuf);
- if (munmap(mmapbuf, CODEC_DEVICE_MEM_SIZE) != 0) {
- CODEC_LOG(ERR, "Failed to release memory region of %s.\n", CODEC_DEV);
- }
- dev->buf = NULL;
-
- ioctl(fd, CODEC_CMD_RELEASE_MEMORY, &dev->mem_info.offset);
-
- CODEC_LOG (INFO, "close %s.\n", CODEC_DEV);
- if (close(fd) != 0) {
- GST_ERROR("Failed to close %s. fd: %d\n", CODEC_DEV, fd);
- }
-
- CODEC_LOG (DEBUG, "leave: %s\n", __func__);
-
- return 0;
-}
-
-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, codec->media_type) < 0) {
- perror("failed to open device.\n");
- return -1;
- }
- ret = codec_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);
-
- CODEC_LOG (DEBUG, "gst_emul_avcodec_close\n");
- codec_deinit (ctx, dev);
-
- ret = gst_emul_codec_device_close (dev);
- g_static_mutex_unlock (&gst_avcodec_mutex);
-
- 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
- *
- */
-
-#ifndef __GST_EMUL_DEV_H__
-#define __GST_EMUL_DEV_H__
-
-int gst_emul_codec_device_open (CodecDevice *dev, int media_type);
-int gst_emul_codec_device_close (CodecDevice *dev);
-
-int gst_emul_avcodec_open (CodecContext *ctx,
- CodecElement *codec,
- CodecDevice *dev);
-int gst_emul_avcodec_close (CodecContext *ctx, 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 "gstemulutils.h"
-#include "gstemulapi.h"
-#include "gstemuldev.h"
-#include <gst/base/gstadapter.h>
-
-#define GST_EMULENC_PARAMS_QDATA g_quark_from_static_string("maruenc-params")
-
-typedef struct _GstEmulEnc
-{
- GstElement element;
-
- GstPad *srcpad;
- GstPad *sinkpad;
-
- CodecContext *context;
- CodecDevice *dev;
- gboolean opened;
- GstClockTime adapter_ts;
- guint64 adapter_consumed;
- GstAdapter *adapter;
- gboolean discont;
-
- // cache
- gulong bitrate;
- gint gop_size;
- gulong buffer_size;
-
- guint8 *working_buf;
- gulong working_buf_size;
-
- GQueue *delay;
-
-} GstEmulEnc;
-
-typedef struct _GstEmulEncClass
-{
- GstElementClass parent_class;
-
- CodecElement *codec;
- GstPadTemplate *sinktempl;
- GstPadTemplate *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 GstCaps *gst_emulenc_getcaps (GstPad *pad);
-
-static GstCaps *gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc,
- GstPad *pad, const GstCaps *caps);
-
-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);
-
-GstStateChangeReturn gst_emulenc_change_state (GstElement *element, GstStateChange transition);
-
-#define DEFAULT_VIDEO_BITRATE 300000
-#define DEFAULT_VIDEO_GOP_SIZE 15
-#define DEFAULT_AUDIO_BITRATE 128000
-
-#define DEFAULT_WIDTH 352
-#define DEFAULT_HEIGHT 288
-
-/*
- * 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;
- CodecElement *codec;
- gchar *longname, *classification, *description;
-
- codec =
- (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
- GST_EMULENC_PARAMS_QDATA);
-
- longname = g_strdup_printf ("%s Encoder", codec->longname);
- classification = g_strdup_printf ("Codec/Encoder/%s",
- (codec->media_type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio");
- description = g_strdup_printf ("%s Encoder", codec->name);
-
- gst_element_class_set_details_simple (element_class,
- longname,
- classification,
- description,
-// "accelerated codec for Tizen Emulator",
- "Kitae Kim <kt920.kim@samsung.com>");
-
- g_free (longname);
- g_free (classification);
-
-
- if (!(srccaps = gst_emul_codecname_to_caps (codec->name, NULL, TRUE))) {
- GST_DEBUG ("Couldn't get source caps for encoder '%s'", codec->name);
- srccaps = gst_caps_new_simple ("unknown/unknown", NULL);
- }
-
- switch (codec->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:
- sinkcaps = gst_emul_codectype_to_audio_caps (NULL, codec->name, TRUE, codec);
- break;
- default:
- GST_LOG("unknown media type.\n");
- break;
- }
-
- if (!sinkcaps) {
- GST_DEBUG ("Couldn't get sink caps for encoder '%s'", 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->codec = codec;
- 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
-
- gstelement_class->change_state = gst_emulenc_change_state;
-
- gobject_class->finalize = gst_emulenc_finalize;
-}
-
-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);
-
- if (oclass->codec->media_type == 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->srcpad, gst_emulenc_event_src);
-
- emulenc->bitrate = DEFAULT_VIDEO_BITRATE;
- emulenc->buffer_size = 512 * 1024;
- emulenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
-#if 0
- emulenc->lmin = 2;
- emulenc->lmax = 31;
-#endif
- } else if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO){
- gst_pad_set_chain_function (emulenc->sinkpad, gst_emulenc_chain_audio);
- emulenc->bitrate = DEFAULT_AUDIO_BITRATE;
- }
-
- gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->sinkpad);
- gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->srcpad);
-
- emulenc->context = g_malloc0 (sizeof(CodecContext));
- emulenc->context->video.pix_fmt = PIX_FMT_NONE;
- emulenc->context->audio.sample_fmt = SAMPLE_FMT_NONE;
-
- emulenc->opened = FALSE;
-
-#if 0
- emulenc->file = NULL;
-#endif
- emulenc->delay = g_queue_new ();
-
- emulenc->dev = g_malloc0 (sizeof(CodecDevice));
- if (!emulenc->dev) {
- printf("failed to allocate memory.\n");
- }
-
- // need to know what adapter does.
- emulenc->adapter = gst_adapter_new ();
-}
-
-static void
-gst_emulenc_finalize (GObject *object)
-{
- // Deinit Decoder
- GstEmulEnc *emulenc = (GstEmulEnc *) object;
-
- if (emulenc->opened) {
- gst_emul_avcodec_close (emulenc->context, emulenc->dev);
- emulenc->opened = FALSE;
- }
-
- if (emulenc->context) {
- g_free (emulenc->context);
- emulenc->context = NULL;
- }
-
- g_queue_free (emulenc->delay);
-#if 0
- g_free (emulenc->filename);
-#endif
-
- g_object_unref (emulenc->adapter);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static GstCaps *
-gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc, GstPad *pad,
- const GstCaps *caps)
-{
- GstCaps *othercaps = NULL;
- GstCaps *tmpcaps = NULL;
- GstCaps *intersect = NULL;
- guint i;
-
- othercaps = gst_pad_peer_get_caps (emulenc->srcpad);
-
- if (!othercaps) {
- return gst_caps_copy (caps);
- }
-
- intersect = gst_caps_intersect (othercaps,
- gst_pad_get_pad_template_caps (emulenc->srcpad));
- gst_caps_unref (othercaps);
-
- if (gst_caps_is_empty (intersect)) {
- return intersect;
- }
-
- if (gst_caps_is_any (intersect)) {
- return gst_caps_copy (caps);
- }
-
- tmpcaps = gst_caps_new_empty ();
-
- for (i = 0; i <gst_caps_get_size (intersect); i++) {
- GstStructure *s = gst_caps_get_structure (intersect, i);
- const GValue *height = NULL;
- const GValue *width = NULL;
- const GValue *framerate = NULL;
- GstStructure *tmps;
-
- height = gst_structure_get_value (s, "height");
- width = gst_structure_get_value (s, "width");
- framerate = gst_structure_get_value (s, "framerate");
-
- tmps = gst_structure_new ("video/x-rwa-rgb", NULL);
- if (width) {
- gst_structure_set_value (tmps, "width", width);
- }
- if (height) {
- gst_structure_set_value (tmps, "height", height);
- }
- if (framerate) {
- gst_structure_set_value (tmps, "framerate", framerate);
- }
- gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
-
- gst_structure_set_name (tmps, "video/x-raw-yuv");
- gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
-
- gst_structure_set_name (tmps, "video/x-raw-gray");
- gst_caps_merge_structure (tmpcaps, tmps);
- }
- gst_caps_unref (intersect);
-
- intersect = gst_caps_intersect (caps, tmpcaps);
- gst_caps_unref (tmpcaps);
-
- return intersect;
-}
-
-static GstCaps *
-gst_emulenc_getcaps (GstPad *pad)
-{
- GstEmulEnc *emulenc = (GstEmulEnc *) GST_PAD_PARENT (pad);
- GstEmulEncClass *oclass =
- (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
- CodecContext *ctx = NULL;
- enum PixelFormat pixfmt;
- GstCaps *caps = NULL;
- GstCaps *finalcaps = NULL;
- gint i;
-
- GST_DEBUG_OBJECT (emulenc, "getting caps");
-
- if (!oclass->codec) {
- GST_ERROR_OBJECT (emulenc, "codec element is null.");
- return NULL;
- }
-
- if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO) {
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
-
- GST_DEBUG_OBJECT (emulenc, "audio caps, return template %" GST_PTR_FORMAT,
- caps);
- return caps;
- }
-
- // cached
- if (oclass->sinkcaps) {
- caps = gst_emulenc_get_possible_sizes (emulenc, pad, oclass->sinkcaps);
- GST_DEBUG_OBJECT (emulenc, "return cached caps %" GST_PTR_FORMAT, caps);
- return caps;
- }
-
- GST_DEBUG_OBJECT (emulenc, "probing caps");
- i = pixfmt = 0;
-
- for (pixfmt = 0;; pixfmt++) {
- GstCaps *tmpcaps;
-
- if ((pixfmt = oclass->codec->pix_fmts[i++]) == PIX_FMT_NONE) {
- GST_DEBUG_OBJECT (emulenc,
- "At the end of official pixfmt for this codec, breaking out");
- break;
- }
-
- GST_DEBUG_OBJECT (emulenc,
- "Got an official pixfmt [%d], attempting to get caps", pixfmt);
- tmpcaps = gst_emul_pixfmt_to_caps (pixfmt, NULL, oclass->codec->name);
- if (tmpcaps) {
- GST_DEBUG_OBJECT (emulenc, "Got caps, breaking out");
- if (!caps) {
- caps = gst_caps_new_empty ();
- }
- gst_caps_append (caps, tmpcaps);
- continue;
- }
-
- GST_DEBUG_OBJECT (emulenc,
- "Couldn't figure out caps without context, trying again with a context");
-
- GST_DEBUG_OBJECT (emulenc, "pixfmt: %d", pixfmt);
- if (pixfmt >= PIX_FMT_NB) {
- GST_WARNING ("Invalid pixfmt, breaking out");
- break;
- }
-
- ctx = g_malloc0 (sizeof(CodecContext));
- if (!ctx) {
- GST_DEBUG_OBJECT (emulenc, "no context");
- break;
- }
-
- ctx->video.width = DEFAULT_WIDTH;
- ctx->video.height = DEFAULT_HEIGHT;
- ctx->video.fps_n = 1;
- ctx->video.fps_d = 25;
- ctx->video.ticks_per_frame = 1;
- ctx->bit_rate = DEFAULT_VIDEO_BITRATE;
-
-// ctx->strict_std_compliance = -1;
- ctx->video.pix_fmt = pixfmt;
-
- GST_DEBUG ("Attempting to open codec");
- if (gst_emul_avcodec_open (ctx, oclass->codec, emulenc->dev) >= 0
- && ctx->video.pix_fmt == pixfmt) {
- ctx->video.width = -1;
- if (!caps) {
- caps = gst_caps_new_empty ();
- }
- tmpcaps = gst_emul_codectype_to_caps (oclass->codec->media_type, ctx,
- oclass->codec->name, TRUE);
- if (tmpcaps) {
- gst_caps_append (caps, tmpcaps);
- } else {
- GST_LOG_OBJECT (emulenc,
- "Couldn't get caps for codec: %s", oclass->codec->name);
- }
- gst_emul_avcodec_close (ctx, emulenc->dev);
- } else {
- GST_DEBUG_OBJECT (emulenc, "Opening codec failed with pixfmt: %d", pixfmt);
- }
-
- gst_emul_avcodec_close (ctx, emulenc->dev);
-#if 0
- if (ctx->priv_data) {
- gst_emul_avcodec_close (ctx, emulenc->dev);
- }
-#endif
- g_free (ctx);
- }
-
- if (!caps) {
- caps = gst_emulenc_get_possible_sizes (emulenc, pad,
- gst_pad_get_pad_template_caps (pad));
- GST_DEBUG_OBJECT (emulenc, "probing gave nothing, "
- "return template %" GST_PTR_FORMAT, caps);
- return caps;
- }
-
- GST_DEBUG_OBJECT (emulenc, "probed caps gave %" GST_PTR_FORMAT, caps);
- oclass->sinkcaps = gst_caps_copy (caps);
-
- finalcaps = gst_emulenc_get_possible_sizes (emulenc, pad, caps);
- gst_caps_unref (caps);
-
- return finalcaps;
-}
-
-static gboolean
-gst_emulenc_setcaps (GstPad *pad, GstCaps *caps)
-{
- GstEmulEnc *emulenc;
- GstEmulEncClass *oclass;
- GstCaps *other_caps;
- GstCaps *allowed_caps;
- GstCaps *icaps;
- enum PixelFormat pix_fmt;
- int32_t buf_size;
-
- emulenc = (GstEmulEnc *) (gst_pad_get_parent (pad));
- oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
-
- if (emulenc->opened) {
- gst_emul_avcodec_close (emulenc->context, emulenc->dev);
- emulenc->opened = FALSE;
-
- gst_pad_set_caps (emulenc->srcpad, NULL);
- }
-
- emulenc->context->bit_rate = emulenc->bitrate;
- GST_DEBUG_OBJECT (emulenc, "Setting context to bitrate %lu, gop_size %d",
- emulenc->bitrate, emulenc->gop_size);
-
-#if 0
-
- // user defined properties
- emulenc->context->gop_size = emulenc->gop_size;
- emulenc->context->lmin = (emulenc->lmin * FF_QP2LAMBDA + 0.5);
- emulenc->context->lmax = (emulenc->lmax * FF_QP2LAMBDA + 0.5);
-
- // some other defaults
- emulenc->context->b_frame_strategy = 0;
- emulenc->context->coder_type = 0;
- emulenc->context->context_model = 0;
- emulenc->context->scenechange_threshold = 0;
- emulenc->context->inter_threshold = 0;
-
- if (emulenc->interlaced) {
- emulenc->context->flags |=
- CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
- emulenc->picture->interlaced_frame = TRUE;
-
- emulenc->picture->top_field_first = TRUE;
- }
-#endif
-
- gst_emul_caps_with_codectype (oclass->codec->media_type, caps, emulenc->context);
-
- if (!emulenc->context->video.fps_d) {
- emulenc->context->video.fps_d = 25;
- emulenc->context->video.fps_n = 1;
- } else if (!strcmp(oclass->codec->name ,"mpeg4")
- && (emulenc->context->video.fps_d > 65535)) {
- emulenc->context->video.fps_n =
- (gint) gst_util_uint64_scale_int (emulenc->context->video.fps_n,
- 65535, emulenc->context->video.fps_d);
- emulenc->context->video.fps_d = 65535;
- GST_LOG_OBJECT (emulenc, "MPEG4 : scaled down framerate to %d / %d",
- emulenc->context->video.fps_d, emulenc->context->video.fps_n);
- }
-
- pix_fmt = emulenc->context->video.pix_fmt;
-
- {
- switch (oclass->codec->media_type) {
- case AVMEDIA_TYPE_VIDEO:
- {
- int width, height;
-
- width = emulenc->context->video.width;
- height = emulenc->context->video.height;
- buf_size = width * height * 6 + FF_MIN_BUFFER_SIZE + 100;
- break;
- }
- case AVMEDIA_TYPE_AUDIO:
- buf_size = FF_MAX_AUDIO_FRAME_SIZE + 100;
- break;
- default:
- buf_size = -1;
- break;
- }
- }
-
- emulenc->dev->buf_size = gst_emul_align_size(buf_size);
-
- // open codec
- if (gst_emul_avcodec_open (emulenc->context,
- oclass->codec, emulenc->dev) < 0) {
- GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to open codec",
- oclass->codec->name);
- return FALSE;
- }
-
- if (pix_fmt != emulenc->context->video.pix_fmt) {
- gst_emul_avcodec_close (emulenc->context, emulenc->dev);
- GST_DEBUG_OBJECT (emulenc,
- "maru_%senc: AV wants different colorspace (%d given, %d wanted)",
- oclass->codec->name, pix_fmt, emulenc->context->video.pix_fmt);
- return FALSE;
- }
-
- if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO
- && pix_fmt == PIX_FMT_NONE) {
- GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to determine input format",
- oclass->codec->name);
- return FALSE;
- }
-
- GST_DEBUG_OBJECT (emulenc, "picking an output format.");
- allowed_caps = gst_pad_get_allowed_caps (emulenc->srcpad);
- if (!allowed_caps) {
- GST_DEBUG_OBJECT (emulenc, "but no peer, using template caps");
- allowed_caps =
- gst_caps_copy (gst_pad_get_pad_template_caps (emulenc->srcpad));
- }
-
- GST_DEBUG_OBJECT (emulenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
- gst_emul_caps_with_codecname (oclass->codec->name,
- oclass->codec->media_type, allowed_caps, emulenc->context);
-
- other_caps =
- gst_emul_codecname_to_caps (oclass->codec->name, emulenc->context, TRUE);
- if (!other_caps) {
- GST_DEBUG("Unsupported codec - no caps found");
- gst_emul_avcodec_close (emulenc->context, emulenc->dev);
- 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);
- gst_caps_unref (icaps);
- icaps = newcaps;
- }
-
- if (!gst_pad_set_caps (emulenc->srcpad, icaps)) {
- gst_emul_avcodec_close (emulenc->context, emulenc->dev);
- gst_caps_unref (icaps);
- return FALSE;
- }
- gst_object_unref (emulenc);
-
- emulenc->opened = TRUE;
-
- return TRUE;
-}
-
-static void
-gst_emulenc_setup_working_buf (GstEmulEnc *emulenc)
-{
- guint wanted_size =
- emulenc->context->video.width * emulenc->context->video.height * 6 +
- FF_MIN_BUFFER_SIZE;
-
- if (emulenc->working_buf == NULL ||
- emulenc->working_buf_size != wanted_size) {
- if (emulenc->working_buf) {
- g_free (emulenc->working_buf);
- }
- emulenc->working_buf_size = wanted_size;
- emulenc->working_buf = g_malloc0 (emulenc->working_buf_size);
- }
- emulenc->buffer_size = wanted_size;
-}
-
-GstFlowReturn
-gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer)
-{
- GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
- GstBuffer *outbuf;
- gint ret_size = 0, frame_size;
-
- GST_DEBUG_OBJECT (emulenc,
- "Received buffer of time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
-
-#if 0
- GST_OBJECT_LOCK (emulenc);
- force_keyframe = emulenc->force_keyframe;
- emulenc->force_keyframe = FALSE;
- GST_OBJECT_UNLOCK (emulenc);
-
- if (force_keyframe) {
- emulenc->picture->pict_type = FF_I_TYPE;
- }
-#endif
-
- frame_size = gst_emul_avpicture_size (emulenc->context->video.pix_fmt,
- emulenc->context->video.width, emulenc->context->video.height);
- g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (buffer),
- GST_FLOW_ERROR);
-
-#if 0
- pts = gst_emul_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buffer) /
- emulenc->context.video.ticks_per_frame,
- emulenc->context.video.fps_n, emulen->context.video.fps_d);
-#endif
-
- // TODO: check whether this func needs or not.
- gst_emulenc_setup_working_buf (emulenc);
-
- ret_size =
- codec_encode_video (emulenc->context, emulenc->working_buf,
- emulenc->working_buf_size, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer), GST_BUFFER_TIMESTAMP (buffer),
- emulenc->dev);
-
- if (ret_size < 0) {
- GstEmulEncClass *oclass =
- (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
- GST_ERROR_OBJECT (emulenc,
- "maru_%senc: failed to encode buffer", oclass->codec->name);
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
-
- g_queue_push_tail (emulenc->delay, buffer);
- if (ret_size) {
- buffer = g_queue_pop_head (emulenc->delay);
- } else {
- return GST_FLOW_OK;
- }
-
-#if 0
- if (emulenc->file && emulenc->context->stats_out) {
- if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
- GST_ELEMENT_ERROR (emulenc, RESOURCE, WRITE,
- (("Could not write to file \"%s\"."), emulenc->filename),
- GST_ERROR_SYSTEM);
- }
- }
-#endif
-#if 1
- {
- int ret;
- uint32_t mem_offset;
- uint8_t *working_buf = NULL;
-
- mem_offset = emulenc->dev->mem_info.offset;
- working_buf = emulenc->dev->buf + mem_offset;
- if (!working_buf) {
- } else {
- CODEC_LOG (INFO,
- "encoded video. mem_offset = 0x%x\n", mem_offset);
-
- outbuf = gst_buffer_new_and_alloc (ret_size);
-// memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
- memcpy (GST_BUFFER_DATA (outbuf), working_buf, ret_size);
- GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
- GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
- }
-
- ret = ioctl(emulenc->dev->fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
- if (ret < 0) {
- CODEC_LOG (ERR, "failed to release used buffer\n");
- }
- }
-#endif
-
-#if 0
- if (emulenc->context->coded_frame) {
- if (!emulenc->context->coded_frame->key_frame) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
- }
- } else {
- GST_WARNING_OBJECT (emulenc, "codec did not provide keyframe info");
- }
-#endif
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
-
- gst_buffer_unref (buffer);
-
-#if 0
-
- if (force_keyframe) {
- gst_pad_push_event (emulenc->srcpad,
- gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
- gst_structure_new ("GstForceKeyUnit", "timestamp",
- G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), NULL)));
- }
-#endif
-
- return gst_pad_push (emulenc->srcpad, outbuf);
-}
-
-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 *audio_out;
- gint res;
- GstFlowReturn ret;
-
- outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE);
- audio_out = GST_BUFFER_DATA (outbuf);
-
- GST_LOG_OBJECT (emulenc, "encoding buffer of max size %d", max_size);
- if (emulenc->buffer_size != max_size) {
- emulenc->buffer_size = max_size;
- }
-
- res = codec_encode_audio (emulenc->context, audio_out, max_size,
- audio_in, in_size, emulenc->dev);
-
- if (res < 0) {
- GST_ERROR_OBJECT (emulenc, "Failed to encode buffer: %d", res);
- gst_buffer_unref (outbuf);
- return GST_FLOW_OK;
- }
- GST_LOG_OBJECT (emulenc, "got output size %d", res);
-
- GST_BUFFER_SIZE (outbuf) = res;
- GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
- GST_BUFFER_DURATION (outbuf) = duration;
- if (discont) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
- }
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
-
- GST_LOG_OBJECT (emulenc, "pushing size %d, timestamp %",
- GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp));
-
- ret = gst_pad_push (emulenc->srcpad, outbuf);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer)
-{
- GstEmulEnc *emulenc;
- GstEmulEncClass *oclass;
- GstClockTime timestamp, duration;
- guint in_size, frame_size;
- gint osize;
- GstFlowReturn ret;
- gint out_size = 0;
- gboolean discont;
- guint8 *in_data;
- CodecContext *ctx;
-
- emulenc = (GstEmulEnc *) (GST_OBJECT_PARENT (pad));
- oclass = (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
-
- ctx = emulenc->context;
-
- in_size = GST_BUFFER_SIZE (buffer);
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
- duration = GST_BUFFER_DURATION (buffer);
- discont = GST_BUFFER_IS_DISCONT (buffer);
-
- GST_DEBUG_OBJECT (emulenc,
- "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
- ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), in_size);
-
- frame_size = ctx->audio.frame_size;
- osize = ctx->audio.bits_per_sample_fmt;
-
- if (frame_size > 1) {
- guint avail, frame_bytes;
-
- if (discont) {
- GST_LOG_OBJECT (emulenc, "DISCONT, clear adapter");
- gst_adapter_clear (emulenc->adapter);
- emulenc->discont = TRUE;
- }
-
- if (gst_adapter_available (emulenc->adapter) == 0) {
- GST_LOG_OBJECT (emulenc, "taking buffer timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (timestamp));
- emulenc->adapter_ts = timestamp;
- emulenc->adapter_consumed = 0;
- } else {
- GstClockTime upstream_time;
- GstClockTime consumed_time;
- guint64 bytes;
-
- consumed_time =
- gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
- ctx->audio.sample_rate);
- timestamp = emulenc->adapter_ts + consumed_time;
- GST_LOG_OBJECT (emulenc, "taking adapter timestamp %" GST_TIME_FORMAT
- " and adding consumed time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (emulenc->adapter_ts), GST_TIME_ARGS (consumed_time));
-
- upstream_time = gst_adapter_prev_timestamp (emulenc->adapter, &bytes);
- if (GST_CLOCK_TIME_IS_VALID (upstream_time)) {
- GstClockTimeDiff diff;
-
- upstream_time +=
- gst_util_uint64_scale (bytes, GST_SECOND,
- ctx->audio.sample_rate * osize * ctx->audio.channels);
- diff = upstream_time - timestamp;
-
- if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) {
- GST_DEBUG_OBJECT (emulenc, "adapter timestamp drifting, "
- "taking upstream timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (upstream_time));
- timestamp = upstream_time;
-
- emulenc->adapter_consumed = bytes / (osize * ctx->audio.channels);
- emulenc->adapter_ts =
- upstream_time - gst_util_uint64_scale (emulenc->adapter_consumed,
- GST_SECOND, ctx->audio.sample_rate);
- emulenc->discont = TRUE;
- }
- }
- }
-
- GST_LOG_OBJECT (emulenc, "pushing buffer in adapter");
- gst_adapter_push (emulenc->adapter, buffer);
-
- frame_bytes = frame_size * osize * ctx->audio.channels;
- avail = gst_adapter_available (emulenc->adapter);
-
- GST_LOG_OBJECT (emulenc, "frame_bytes %u, avail %u", frame_bytes, avail);
-
- while (avail >= frame_bytes) {
- GST_LOG_OBJECT (emulenc, "taking %u bytes from the adapter", frame_bytes);
-
- in_data = (guint8 *) gst_adapter_peek (emulenc->adapter, frame_bytes);
- emulenc->adapter_consumed += frame_size;
-
- duration =
- gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
- ctx->audio.sample_rate);
- duration -= (timestamp - emulenc->adapter_ts);
-
- out_size = frame_bytes * 4;
-
- ret =
- gst_emulenc_encode_audio (emulenc, in_data, frame_bytes, out_size,
- timestamp, duration, emulenc->discont);
-
- gst_adapter_flush (emulenc->adapter, frame_bytes);
- if (ret != GST_FLOW_OK) {
- GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
- gst_flow_get_name (ret));
- }
-
- timestamp += duration;
-
- emulenc->discont = FALSE;
- avail = gst_adapter_available (emulenc->adapter);
- }
- GST_LOG_OBJECT (emulenc, "%u bytes left in the adapter", avail);
- } else {
-#if 0
- int coded_bps = av_get_bits_per_sample (oclass->codec->name);
-
- GST_LOG_OBJECT (emulenc, "coded bps %d, osize %d", coded_bps, osize);
-
- out_size = in_size / osize;
- if (coded_bps) {
- out_size = (out_size * coded_bps) / 8;
- }
-#endif
- in_data = (guint8 *) GST_BUFFER_DATA (buffer);
- ret = gst_emulenc_encode_audio (emulenc, in_data, in_size, out_size,
- timestamp, duration, discont);
- gst_buffer_unref (buffer);
- if (ret != GST_FLOW_OK) {
- GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
- gst_flow_get_name (ret));
- }
- }
-
- return GST_FLOW_OK;
-}
-
-static void
-gst_emulenc_flush_buffers (GstEmulEnc *emulenc, gboolean send)
-{
- GstBuffer *outbuf, *inbuf;
- gint ret_size = 0;
-
- GST_DEBUG_OBJECT (emulenc, "flushing buffers with sending %d", send);
-
- if (!emulenc->opened) {
- while (!g_queue_is_empty (emulenc->delay)) {
- gst_buffer_unref (g_queue_pop_head (emulenc->delay));
- }
- }
-
-#if 0
- while (!g_queue_is_empty (emulenc->delay)) {
- emulenc_setup_working_buf (emulenc);
-
- ret_size = codec_encode_video (emulenc->context,
- emulenc->working_buf, emulenc->working_buf_size, NULL, NULL, 0,
- emulenc->dev);
-
- if (ret_size < 0) {
- GstEmulEncClass *oclass =
- (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
- GST_WARNING_OBJECT (emulenc,
- "maru_%senc: failed to flush buffer", oclass->codec->name);
- break;
- }
-
- if (emulenc->file && emulenc->context->stats_out) {
- if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
- GST_ELEMENT_ERROR (emeulenc, RESOURCE, WRITE,
- (("Could not write to file \"%s\"."), emulenc->filename),
- GST_ERROR_SYSTEM);
- }
- }
-
- inbuf = g_queue_pop_head (emulenc->delay);
-
- outbuf = gst_buffer_new_and_alloc (ret_size);
- memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
- GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
- GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
-
- if (!emulenc->context->coded_frame->key_frame) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
- }
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
-
- gst_buffer_unref (inbuf);
-
- if (send) {
- gst_pad_push (emulenc->srcpad, outbuf);
- } else {
- gst_buffer_unref (outbuf);
- }
- }
-
- while (!g_queue_is_empty (emulenc->delay)) {
- gst_buffer_unref (g_queue_pop_head (emulenc->delay));
- }
-#endif
-}
-
-static gboolean
-gst_emulenc_event_video (GstPad *pad, GstEvent *event)
-{
- GstEmulEnc *emulenc;
- emulenc = (GstEmulEnc *) gst_pad_get_parent (pad);
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- gst_emulenc_flush_buffers (emulenc, TRUE);
- break;
- case GST_EVENT_CUSTOM_DOWNSTREAM:
- {
- const GstStructure *s;
- s = gst_event_get_structure (event);
-
- if (gst_structure_has_name (s, "GstForceKeyUnit")) {
-#if 0
- emulenc->picture->pict_type = FF_I_TYPE;
-#endif
- }
- }
- break;
- default:
- break;
- }
-
- return gst_pad_push_event (emulenc->srcpad, event);
-}
-
-static gboolean
-gst_emulenc_event_src (GstPad *pad, GstEvent *event)
-{
- GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
- gboolean forward = TRUE;
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_CUSTOM_UPSTREAM:
- {
- const GstStructure *s;
- s = gst_event_get_structure (event);
-
- if (gst_structure_has_name (s, "GstForceKeyUnit")) {
-#if 0
- GST_OBJECT_LOCK (emulenc);
- emulenc->force_keyframe = TRUE;
- GST_OBJECT_UNLOCK (emulenc);
-#endif
- forward = FALSE;
- gst_event_unref (event);
- }
- }
- break;
- default:
- break;
- }
-
- if (forward) {
- return gst_pad_push_event (emulenc->sinkpad, event);
- }
-
- return TRUE;
-}
-
-GstStateChangeReturn
-gst_emulenc_change_state (GstElement *element, GstStateChange transition)
-{
- GstEmulEnc *emulenc = (GstEmulEnc*)element;
- GstStateChangeReturn ret;
-
- switch (transition) {
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_emulenc_flush_buffers (emulenc, FALSE);
- if (emulenc->opened) {
- gst_emul_avcodec_close (emulenc->context, emulenc->dev);
- emulenc->opened = FALSE;
- }
- gst_adapter_clear (emulenc->adapter);
-
-#if 0
- if (emulenc->flie) {
- fclose (emulenc->file);
- emulenc->file = NULL;
- }
-#endif
-
- if (emulenc->working_buf) {
- g_free (emulenc->working_buf);
- emulenc->working_buf = NULL;
- }
- break;
- 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_NONE;
- GList *elem = element;
- CodecElement *codec = NULL;
-
- if (!elem) {
- return FALSE;
- }
-
- /* register element */
- do {
- codec = (CodecElement *)(elem->data);
- if (!codec) {
- return FALSE;
- }
-
- if (codec->codec_type != CODEC_TYPE_ENCODE) {
- continue;
- }
-
- type_name = g_strdup_printf ("maru_%senc", 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_EMULENC_PARAMS_QDATA, (gpointer) codec);
- }
-
- if (!gst_element_register (plugin, type_name, rank, type)) {
- g_free (type_name);
- return FALSE;
- }
- g_free (type_name);
- } while ((elem = elem->next));
-
- return TRUE;
-}
+++ /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, pixel format: %d",
- ctx, name, encode, ctx->video.pix_fmt);
-
- 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 (ctx) {
- caps = gst_emul_smpfmt_to_caps (ctx->audio.sample_fmt, ctx, name);
-#if 1
- } else if (codec && codec->sample_fmts[0] != -1){
- GstCaps *temp;
- int i;
-
- caps = gst_caps_new_empty ();
- for (i = 0; codec->sample_fmts[i] != -1; i++) {
- temp =
- gst_emul_smpfmt_to_caps (codec->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);
- ctx->video.ticks_per_frame = 1;
-
- 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;
- }
- }
-// printf ("get pixel format: %d, fourcc: %d\n", ctx->video.pix_fmt, fourcc);
- } 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);
- gst_structure_get_int (str, "bitrate", &ctx->bit_rate);
-
- if (!raw) {
- return;
- }
-
- name = gst_structure_get_name (str);
-
- 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 (gst_structure_get_int (str, "width", &width) &&
- gst_structure_get_int (str, "depth", &depth) &&
- gst_structure_get_boolean (str, "signed", &signedness) &&
- gst_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 = SAMPLE_FMT_S32;
- }
- }
- }
- }
-}
-
-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);
- GST_DEBUG ("extradata: %p, size: %d\n", data, 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 (!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');
- }
-#if 0
- } else if (strcmp (name, "h263p") == 0) {
- gboolean val;
-
- 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;
- }
-
-}
-
-void
-gst_emul_caps_with_codectype (int media_type, const GstCaps *caps, CodecContext *ctx)
-{
- if (ctx == NULL) {
- return;
- }
-
- switch (media_type) {
- case AVMEDIA_TYPE_VIDEO:
- gst_emul_caps_to_pixfmt (caps, ctx, TRUE);
- break;
- case AVMEDIA_TYPE_AUDIO:
- gst_emul_caps_to_smpfmt (caps, ctx, TRUE);
- 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, NULL);
-
- num = ctx->video.fps_d / ctx->video.ticks_per_frame;
- denom = ctx->video.fps_n;
-
- 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 (strcmp (name, "h263") == 0) {
- /* 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 if (strcmp (name, "none") == 0) {
- GST_LOG ("default caps");
- }
- }
-
- /* 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, "none", "video/x-h263",
- "variant", G_TYPE_STRING, "itu", 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
- switch (ctx->codec_tag) {
- case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
- caps = gst_emul_video_caps_new (ctx, name, "video/x-divx",
- "divxversion", G_TYPE_INT, 5, NULL);
- break;
- case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
- default:
- caps = gst_emul_video_caps_new (ctx, name, "video/mpeg",
- "systemstream", G_TYPE_BOOLEAN, FALSE,
- "mpegversion", G_TYPE_INT, 4, NULL);
- break;
- }
- } 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 (ctx && ctx->codecdata_size > 0) {
- gst_codec_utils_aac_caps_set_level_and_profile (caps,
- ctx->codecdata, ctx->codecdata_size);
- }
- }
- } 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 (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 {
- 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];
-
-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;
-}
-
-int
-gst_emul_align_size (int buf_size)
-{
- int i, align_size;
-
- align_size = buf_size / 1024;
-
- for (i = 0; i < 14; i++) {
- if (align_size < (1 << i)) {
- align_size = 1024 * (1 << i);
- break;
- }
- }
-
- return align_size;
-}
+++ /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);
-
-void gst_emul_caps_with_codectype (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);
-
-void gst_emul_init_pix_fmt_info (void);
-
-int gst_emul_avpicture_size (int pix_fmt, int width, int height);
-
-int gst_emul_align_size (int buf_size);
-
-gint gst_emul_smpfmt_depth (int smp_fmt);
-
-#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+/* First, include the header file for the plugin, to bring in the
+ * object definition and other useful things.
+ */
+
+/*
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "gstmaru.h"
+
+GST_DEBUG_CATEGORY (maru_debug);
+
+#define GST_TYPE_EMULDEC \
+ (gst_maru_dec_get_type())
+#define GST_EMULDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EMULDEC,GstEmulDec))
+#define GST_EMULDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EMULDEC,GstEmulDecClass))
+#define GST_IS_EMULDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EMULDEC))
+#define GST_IS_EMULDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EMULDEC))
+
+gboolean gst_marudec_register (GstPlugin *plugin, GList *element);
+gboolean gst_maruenc_register (GstPlugin *plugin, GList *element);
+
+static GList *codec_element = NULL;
+
+static gboolean
+gst_maru_codec_element_init ()
+{
+ int fd = 0, size = 0;
+ int version = 0;
+ int data_length = 0;
+ int i, elem_cnt = 0;
+ void *buffer = NULL;
+ CodecElement *elem = NULL;
+
+ fd = open (CODEC_DEV, O_RDWR);
+ if (fd < 0) {
+ perror ("[gst-maru] failed to open codec device");
+ return FALSE;
+ }
+
+ ioctl (fd, CODEC_CMD_GET_VERSION, &version);
+ if (version != CODEC_VER) {
+ CODEC_LOG (INFO, "version conflict between device: %d, plugin: %d\n",
+ version, CODEC_VER);
+ close (fd);
+ return FALSE;
+ }
+
+ buffer = mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (!buffer) {
+ perror ("[gst-maru] failure memory mapping.");
+ close (fd);
+ return FALSE;
+ }
+
+ CODEC_LOG (DEBUG, "request a device to get codec element.\n");
+ if (ioctl(fd, CODEC_CMD_GET_ELEMENT, NULL) < 0) {
+ perror ("[gst-maru] failed to get codec elements");
+ munmap (buffer, 4096);
+ close (fd);
+ return FALSE;
+ }
+
+ memcpy(&data_length, (uint8_t *)buffer, sizeof(data_length));
+ size += sizeof(data_length);
+
+ elem = g_malloc0 (data_length);
+ if (!elem) {
+ CODEC_LOG (ERR, "Failed to allocate memory.\n");
+ munmap (buffer, 4096);
+ close (fd);
+ return FALSE;
+ }
+
+ memcpy (elem, (uint8_t *)buffer + size, data_length);
+
+ elem_cnt = data_length / sizeof(CodecElement);
+ for (i = 0; i < elem_cnt; i++) {
+ codec_element = g_list_append (codec_element, &elem[i]);
+ }
+
+ munmap (buffer, 4096);
+ close (fd);
+
+ return TRUE;
+}
+
+static gboolean
+plugin_init (GstPlugin *plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (maru_debug,
+ "tizen-maru", 0, "Tizen Emulator Codec Elements");
+
+ gst_maru_init_pix_fmt_info ();
+
+ if (!gst_maru_codec_element_init ()) {
+ GST_ERROR ("failed to get codec elements from QEMU");
+ return FALSE;
+ }
+
+ if (!gst_marudec_register (plugin, codec_element)) {
+ GST_ERROR ("failed to register decoder elements");
+ return FALSE;
+ }
+ if (!gst_maruenc_register (plugin, codec_element)) {
+ GST_ERROR ("failed to register encoder elements");
+ return FALSE;
+ }
+
+#if 0
+ while ((codec_element = g_list_next (codec_element))) {
+ g_list_free (codec_element);
+ }
+#endif
+
+ return TRUE;
+}
+
+#ifndef PACKAGE
+#define PACKAGE "gst-plugins-maruator"
+#endif
+
+GST_PLUGIN_DEFINE (
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "tizen-emul",
+ "Codecs for Tizen Emulator",
+ plugin_init,
+ "0.1.1",
+ "LGPL",
+ "gst-plugins-emulator",
+ "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
+ *
+ */
+
+#ifndef __GST_MARU_H__
+#define __GST_MARU_H__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.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 (maru_debug);
+#define GST_CAT_DEFAULT maru_debug
+
+G_BEGIN_DECLS
+
+enum codec_log_level {
+ ERR,
+ WARN,
+ INFO,
+ DEBUG,
+};
+
+#define CODEC_DEV "/dev/brillcodec"
+#define CODEC_VER 1
+
+#define CODEC_LOG(level, fmt, ...) \
+ do { \
+ if (level <= INFO) \
+ printf("[gst-maru][%d] " fmt, __LINE__, ##__VA_ARGS__); \
+ } while (0)
+
+#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
+
+#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))
+
+typedef struct _CodecIOParams {
+ int32_t api_index;
+ int32_t ctx_index;
+ uint32_t mem_offset;
+} CodecIOParams;
+
+typedef struct _CodecDeviceMem {
+ uint32_t index;
+ uint32_t offset;
+} CodecDeviceMem;
+
+typedef struct _CodecDevice {
+ int fd;
+ uint8_t *buf;
+ uint32_t buf_size;
+ CodecDeviceMem mem_info;
+} CodecDevice;
+
+typedef struct _CodecElement {
+ int32_t codec_type;
+ int32_t media_type;
+ gchar name[32];
+ gchar longname[64];
+ union {
+ int32_t pix_fmts[4];
+ int32_t sample_fmts[4];
+ };
+} CodecElement;
+
+typedef struct _VideoData {
+ int32_t width, height;
+ int32_t fps_n, fps_d;
+ int32_t par_n, par_d;
+ int32_t pix_fmt, bpp;
+ int32_t ticks_per_frame;
+} VideoData;
+
+typedef struct _AudioData {
+ int32_t channels, sample_rate;
+ int32_t block_align, depth;
+ int32_t sample_fmt, frame_size;
+ int32_t bits_per_sample_fmt;
+ int64_t channel_layout;
+} AudioData;
+
+typedef struct _CodecContext {
+// union {
+ VideoData video;
+ AudioData audio;
+// };
+
+ int32_t bit_rate;
+ int32_t codec_tag;
+
+ int32_t codecdata_size;
+ uint8_t *codecdata;
+
+ CodecElement *codec;
+ int32_t index;
+} CodecContext;
+
+enum CODEC_FUNC_TYPE {
+ CODEC_INIT = 0,
+ CODEC_DECODE_VIDEO,
+ CODEC_ENCODE_VIDEO,
+ CODEC_DECODE_AUDIO,
+ CODEC_ENCODE_AUDIO,
+ CODEC_PICTURE_COPY,
+ CODEC_DEINIT,
+};
+
+#if 0
+enum CODEC_IO_CMD {
+ CODEC_CMD_COPY_TO_DEVICE_MEM = 5,
+ CODEC_CMD_COPY_FROM_DEVICE_MEM,
+ CODEC_CMD_GET_VERSION = 20,
+ CODEC_CMD_GET_ELEMENT,
+ CODEC_CMD_GET_CONTEXT_INDEX,
+ CODEC_CMD_SECURE_MEMORY = 30,
+ CODEC_CMD_RELEASE_MEMORY,
+ CODEC_CMD_USE_DEVICE_MEM,
+ CODEC_CMD_REQ_FROM_SMALL_MEMORY,
+ CODEC_CMD_REQ_FROM_MEDIUM_MEMORY,
+ CODEC_CMD_REQ_FROM_LARGE_MEMORY,
+ CODEC_CMD_S_SECURE_BUFFER,
+ CODEC_CMD_M_SECURE_BUFFER,
+ CODEC_CMD_L_SECURE_BUFFER,
+};
+#endif
+
+enum CODEC_IO_CMD {
+ CODEC_CMD_GET_VERSION = 20,
+ CODEC_CMD_GET_ELEMENT,
+ CODEC_CMD_GET_CONTEXT_INDEX,
+ CODEC_CMD_USE_DEVICE_MEM = 40,
+ CODEC_CMD_GET_DATA_FROM_SMALL_BUFFER,
+ CODEC_CMD_GET_DATA_FROM_MEDIUM_BUFFER,
+ CODEC_CMD_GET_DATA_FROM_LARGE_BUFFER,
+ CODEC_CMD_SECURE_SMALL_BUFFER,
+ CODEC_CMD_SECURE_MEDIUM_BUFFER,
+ CODEC_CMD_SECURE_LARGE_BUFFER,
+ CODEC_CMD_RELEASE_BUFFER,
+};
+
+
+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,
+ SAMPLE_FMT_S16,
+ SAMPLE_FMT_S32,
+ SAMPLE_FMT_FLT,
+ SAMPLE_FMT_DBL,
+ SAMPLE_FMT_NB
+};
+
+G_END_DECLS
+#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 "gstmaru.h"
+#include "gstmaruutils.h"
+#include "gstmaruinterface.h"
+#include "gstmarudevice.h"
+
+#define GST_MARUDEC_PARAMS_QDATA g_quark_from_static_string("marudec-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 opened;
+ 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_marudec_base_init (GstEmulDecClass *klass);
+static void gst_marudec_class_init (GstEmulDecClass *klass);
+static void gst_marudec_init (GstEmulDec *marudec);
+static void gst_marudec_finalize (GObject *object);
+
+static gboolean gst_marudec_setcaps (GstPad *pad, GstCaps *caps);
+
+// sinkpad
+static gboolean gst_marudec_sink_event (GstPad *pad, GstEvent *event);
+static GstFlowReturn gst_marudec_chain (GstPad *pad, GstBuffer *buffer);
+
+// srcpad
+static gboolean gst_marudec_src_event (GstPad *pad, GstEvent *event);
+static GstStateChangeReturn gst_marudec_change_state (GstElement *element,
+ GstStateChange transition);
+
+static gboolean gst_marudec_negotiate (GstEmulDec *dec, gboolean force);
+
+static gint gst_marudec_frame (GstEmulDec *marudec, guint8 *data,
+ guint size, gint *got_data,
+ const GstTSInfo *dec_info, gint64 in_offset, GstFlowReturn *ret);
+
+static gboolean gst_marudec_open (GstEmulDec *marudec);
+static int gst_marudec_close (GstEmulDec *marudec);
+
+
+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_marudec_reset_ts (GstEmulDec *marudec)
+{
+ marudec->next_out = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_marudec_update_qos (GstEmulDec *marudec, gdouble proportion,
+ GstClockTime timestamp)
+{
+ GST_LOG_OBJECT (marudec, "update QOS: %f, %" GST_TIME_FORMAT,
+ proportion, GST_TIME_ARGS (timestamp));
+
+ GST_OBJECT_LOCK (marudec);
+ marudec->proportion = proportion;
+ marudec->earliest_time = timestamp;
+ GST_OBJECT_UNLOCK (marudec);
+}
+
+static void
+gst_marudec_reset_qos (GstEmulDec *marudec)
+{
+ gst_marudec_update_qos (marudec, 0.5, GST_CLOCK_TIME_NONE);
+ marudec->processed = 0;
+ marudec->dropped = 0;
+}
+
+static gboolean
+gst_marudec_do_qos (GstEmulDec *marudec, 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))) {
+ marudec->processed++;
+ return TRUE;
+ }
+
+ proportion = marudec->proportion;
+ earliest_time = marudec->earliest_time;
+
+ qostime = gst_segment_to_running_time (&marudec->segment, GST_FORMAT_TIME,
+ timestamp);
+
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime))) {
+ marudec->processed++;
+ return TRUE;
+ }
+
+ diff = GST_CLOCK_DIFF (qostime, earliest_time);
+
+ if (proportion < 0.4 && diff < 0 ){
+ marudec->processed++;
+ return TRUE;
+ } else {
+ if (diff >= 0) {
+// if (marudec->waiting_for_key) {
+ if (0) {
+ res = FALSE;
+ } else {
+ }
+
+ GstClockTime stream_time, jitter;
+ GstMessage *qos_msg;
+
+ marudec->dropped++;
+ stream_time =
+ gst_segment_to_stream_time (&marudec->segment, GST_FORMAT_TIME,
+ timestamp);
+ jitter = GST_CLOCK_DIFF (qostime, earliest_time);
+ qos_msg =
+ gst_message_new_qos (GST_OBJECT_CAST (marudec), 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,
+ marudec->processed, marudec->dropped);
+ gst_element_post_message (GST_ELEMENT_CAST (marudec), qos_msg);
+
+ return res;
+ }
+ }
+
+ marudec->processed++;
+ return TRUE;
+}
+
+static void
+clear_queued (GstEmulDec *marudec)
+{
+ g_list_foreach (marudec->queued, (GFunc) gst_mini_object_unref, NULL);
+ g_list_free (marudec->queued);
+ marudec->queued = NULL;
+}
+
+static GstFlowReturn
+flush_queued (GstEmulDec *marudec)
+{
+ GstFlowReturn res = GST_FLOW_OK;
+
+ CODEC_LOG (DEBUG, "flush queued\n");
+
+ while (marudec->queued) {
+ GstBuffer *buf = GST_BUFFER_CAST (marudec->queued->data);
+
+ GST_LOG_OBJECT (marudec, "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 (marudec->srcpad, buf);
+
+ marudec->queued =
+ g_list_delete_link (marudec->queued, marudec->queued);
+ }
+
+ return res;
+}
+
+static void
+gst_marudec_drain (GstEmulDec *marudec)
+{
+ GstEmulDecClass *oclass;
+
+ oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (marudec));
+
+ // TODO: drain
+#if 1
+ {
+ gint have_data, len, try = 0;
+
+ do {
+ GstFlowReturn ret;
+
+ len =
+ gst_marudec_frame (marudec, NULL, 0, &have_data, &ts_info_none, 0, &ret);
+
+ if (len < 0 || have_data == 0) {
+ break;
+ }
+ } while (try++ < 10);
+ }
+#endif
+
+ if (marudec->segment.rate < 0.0) {
+ CODEC_LOG (DEBUG, "reverse playback\n");
+ flush_queued (marudec);
+ }
+}
+
+/*
+ * Implementation
+ */
+static void
+gst_marudec_base_init (GstEmulDecClass *klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstCaps *sinkcaps = NULL, *srccaps = NULL;
+ GstPadTemplate *sinktempl, *srctempl;
+ CodecElement *codec;
+ gchar *longname, *classification, *description;
+
+ codec =
+ (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
+ GST_MARUDEC_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");
+ description = g_strdup_printf("%s Decoder", codec->name);
+
+ gst_element_class_set_details_simple (element_class,
+ longname,
+ classification,
+ description,
+ "Kitae Kim <kt920.kim@samsung.com>");
+
+ g_free (longname);
+ g_free (classification);
+ g_free (description);
+
+ sinkcaps = gst_maru_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_maru_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_marudec_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_marudec_set_property
+ gobject_class->get_property = gst_marudec_get_property
+#endif
+
+ gobject_class->finalize = gst_marudec_finalize;
+ gstelement_class->change_state = gst_marudec_change_state;
+}
+
+static void
+gst_marudec_init (GstEmulDec *marudec)
+{
+ GstEmulDecClass *oclass;
+
+ oclass = (GstEmulDecClass*) (G_OBJECT_GET_CLASS(marudec));
+
+ marudec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
+ gst_pad_set_setcaps_function (marudec->sinkpad,
+ GST_DEBUG_FUNCPTR(gst_marudec_setcaps));
+ gst_pad_set_event_function (marudec->sinkpad,
+ GST_DEBUG_FUNCPTR(gst_marudec_sink_event));
+ gst_pad_set_chain_function (marudec->sinkpad,
+ GST_DEBUG_FUNCPTR(gst_marudec_chain));
+
+ marudec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src") ;
+ gst_pad_use_fixed_caps (marudec->srcpad);
+ gst_pad_set_event_function (marudec->srcpad,
+ GST_DEBUG_FUNCPTR(gst_marudec_src_event));
+
+ gst_element_add_pad (GST_ELEMENT(marudec), marudec->sinkpad);
+ gst_element_add_pad (GST_ELEMENT(marudec), marudec->srcpad);
+
+ marudec->context = g_malloc0 (sizeof(CodecContext));
+ marudec->context->video.pix_fmt = PIX_FMT_NONE;
+ marudec->context->audio.sample_fmt = SAMPLE_FMT_NONE;
+
+ marudec->opened = FALSE;
+ marudec->format.video.par_n = -1;
+ marudec->format.video.fps_n = -1;
+ marudec->format.video.old_fps_n = -1;
+
+ marudec->queued = NULL;
+ gst_segment_init (&marudec->segment, GST_FORMAT_TIME);
+
+ marudec->dev = g_malloc0 (sizeof(CodecDevice));
+ if (!marudec->dev) {
+ CODEC_LOG (ERR, "failed to allocate memory.\n");
+ }
+}
+
+static void
+gst_marudec_finalize (GObject *object)
+{
+ GstEmulDec *marudec = (GstEmulDec *) object;
+
+ if (marudec->context) {
+ g_free (marudec->context);
+ marudec->context = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_marudec_src_event (GstPad *pad, GstEvent *event)
+{
+ GstEmulDec *marudec;
+ gboolean res;
+
+ marudec = (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;
+
+ gst_event_parse_qos (event, &proportion, &diff, ×tamp);
+
+ /* update our QoS values */
+ gst_marudec_update_qos (marudec, proportion, timestamp + diff);
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* forward upstream */
+ res = gst_pad_push_event (marudec->sinkpad, event);
+
+ gst_object_unref (marudec);
+
+ return res;
+}
+
+static gboolean
+gst_marudec_sink_event (GstPad *pad, GstEvent *event)
+{
+ GstEmulDec *marudec;
+ gboolean ret = FALSE;
+
+ marudec = (GstEmulDec *) gst_pad_get_parent (pad);
+
+ GST_DEBUG_OBJECT (marudec, "Handling %s event",
+ GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ gst_marudec_drain (marudec);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ {
+#if 0
+ if (marudec->opened) {
+ // TODO: what does avcodec_flush_buffers do?
+ maru_avcodec_flush_buffers (marudec->context, marudec->dev);
+ }
+#endif
+ gst_marudec_reset_ts (marudec);
+ gst_marudec_reset_qos (marudec);
+#if 0
+ gst_marudec_flush_pcache (marudec);
+ marudec->waiting_for_key = TRUE;
+#endif
+ gst_segment_init (&marudec->segment, GST_FORMAT_TIME);
+ clear_queued (marudec);
+ }
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ {
+ gboolean update;
+ GstFormat format;
+ gint64 start, stop, time;
+ gdouble rate, arate;
+
+ gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
+ &start, &stop, &time);
+
+ switch (format) {
+ case GST_FORMAT_TIME:
+ break;
+ case GST_FORMAT_BYTES:
+ {
+ gint bit_rate;
+ bit_rate = marudec->context->bit_rate;
+
+ if (!bit_rate) {
+ GST_WARNING_OBJECT (marudec, "no bitrate to convert BYTES to TIME");
+ gst_event_unref (event);
+ gst_object_unref (marudec);
+ return ret;
+ }
+
+ GST_DEBUG_OBJECT (marudec, "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:
+ GST_WARNING_OBJECT (marudec, "unknown format received in NEWSEGMENT");
+ gst_event_unref (event);
+ gst_object_unref (marudec);
+ return ret;
+ }
+
+ if (marudec->context->codec) {
+ gst_marudec_drain (marudec);
+ }
+
+ GST_DEBUG_OBJECT (marudec,
+ "NEWSEGMENT in time start %" GST_TIME_FORMAT " -- stop %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+ gst_segment_set_newsegment_full (&marudec->segment, update,
+ rate, arate, format, start, stop, time);
+ break;
+ }
+ default:
+ break;
+ }
+
+ ret = gst_pad_push_event (marudec->srcpad, event);
+
+ gst_object_unref (marudec);
+
+ return ret;
+}
+
+
+
+static gboolean
+gst_marudec_setcaps (GstPad *pad, GstCaps *caps)
+{
+ GstEmulDec *marudec;
+ GstEmulDecClass *oclass;
+ GstStructure *structure;
+ const GValue *par;
+ const GValue *fps;
+ gboolean ret = TRUE;
+
+ GST_DEBUG_OBJECT (pad, "setcaps called.");
+
+ marudec = (GstEmulDec *) (gst_pad_get_parent (pad));
+ oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (marudec));
+
+ GST_OBJECT_LOCK (marudec);
+
+ if (marudec->opened) {
+ GST_OBJECT_UNLOCK (marudec);
+ gst_marudec_drain (marudec);
+ GST_OBJECT_LOCK (marudec);
+ gst_marudec_close (marudec);
+ }
+
+ GST_LOG_OBJECT (marudec, "size %dx%d", marudec->context->video.width,
+ marudec->context->video.height);
+
+ if (!strcmp(oclass->codec->name, "wmv3") ||
+ !strcmp(oclass->codec->name, "vc1")) {
+ gst_maru_caps_to_codecname (caps, oclass->codec->name, NULL);
+ }
+
+ gst_maru_caps_with_codecname (oclass->codec->name, oclass->codec->media_type,
+ caps, marudec->context);
+
+ GST_LOG_OBJECT (marudec, "size after %dx%d", marudec->context->video.width,
+ marudec->context->video.height);
+
+ if (!marudec->context->video.fps_d || !marudec->context->video.fps_n) {
+ GST_DEBUG_OBJECT (marudec, "forcing 25/1 framerate");
+ marudec->context->video.fps_n = 1;
+ marudec->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 (marudec, "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 (marudec->par) {
+ g_free(marudec->par);
+ }
+ marudec->par = g_new0 (GValue, 1);
+ gst_value_init_and_copy (marudec->par, par);
+#endif
+ }
+
+ fps = gst_structure_get_value (structure, "framerate");
+ if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) {
+ marudec->format.video.fps_n = gst_value_get_fraction_numerator (fps);
+ marudec->format.video.fps_d = gst_value_get_fraction_denominator (fps);
+ GST_DEBUG_OBJECT (marudec, "Using framerate %d/%d from incoming",
+ marudec->format.video.fps_n, marudec->format.video.fps_d);
+ } else {
+ marudec->format.video.fps_n = -1;
+ GST_DEBUG_OBJECT (marudec, "Using framerate from codec");
+ }
+
+#if 0
+ if (strcmp (oclass->codec->name, "aac") == 0) {
+ const gchar *format = gst_structure_get_string (structure, "stream-format");
+ if (format == NULL || strcmp ("format", "raw") == 0) {
+ marudec->turnoff_parser = TRUE;
+ }
+ }
+#endif
+
+ if (!gst_marudec_open (marudec)) {
+ GST_DEBUG_OBJECT (marudec, "Failed to open");
+#if 0
+ if (marudec->par) {
+ g_free(marudec->par);
+ marudec->par = NULL;
+ }
+#endif
+ GST_OBJECT_UNLOCK (marudec);
+ gst_object_unref (marudec);
+
+ return FALSE;
+ }
+
+ gst_structure_get_int (structure, "width",
+ &marudec->format.video.clip_width);
+ gst_structure_get_int (structure, "height",
+ &marudec->format.video.clip_height);
+
+ GST_DEBUG_OBJECT (pad, "clipping to %dx%d",
+ marudec->format.video.clip_width, marudec->format.video.clip_height);
+
+ GST_OBJECT_UNLOCK (marudec);
+ gst_object_unref (marudec);
+
+ return ret;
+}
+
+static gboolean
+gst_marudec_open (GstEmulDec *marudec)
+{
+ GstEmulDecClass *oclass;
+
+ oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (marudec));
+
+ if (!marudec->dev) {
+ return FALSE;
+ }
+
+ if (gst_maru_avcodec_open (marudec->context,
+ oclass->codec, marudec->dev) < 0) {
+ gst_marudec_close (marudec);
+ GST_ERROR_OBJECT (marudec,
+ "maru_%sdec: Failed to open codec", oclass->codec->name);
+ return FALSE;
+ }
+
+ marudec->opened = TRUE;
+ GST_LOG_OBJECT (marudec, "Opened codec %s", oclass->codec->name);
+
+ switch (oclass->codec->media_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ marudec->format.video.width = 0;
+ marudec->format.video.height = 0;
+ marudec->format.video.clip_width = -1;
+ marudec->format.video.clip_height = -1;
+ marudec->format.video.pix_fmt = PIX_FMT_NB;
+ marudec->format.video.interlaced = FALSE;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ marudec->format.audio.samplerate = 0;
+ marudec->format.audio.channels = 0;
+ marudec->format.audio.depth = 0;
+ break;
+ default:
+ break;
+ }
+
+ gst_marudec_reset_ts (marudec);
+
+ marudec->proportion = 0.0;
+ marudec->earliest_time = -1;
+
+ return TRUE;
+}
+
+static int
+gst_marudec_close (GstEmulDec *marudec)
+{
+ int ret = 0;
+
+ if (marudec->context->codecdata) {
+ g_free(marudec->context->codecdata);
+ marudec->context->codecdata = NULL;
+ }
+
+ if (!marudec->dev) {
+ return -1;
+ }
+
+ ret = gst_maru_avcodec_close (marudec->context, marudec->dev);
+
+ if (marudec->dev) {
+ g_free(marudec->dev);
+ marudec->dev = NULL;
+ }
+
+ return ret;
+}
+
+
+static gboolean
+gst_marudec_negotiate (GstEmulDec *marudec, gboolean force)
+{
+ GstEmulDecClass *oclass;
+ GstCaps *caps;
+
+ oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (marudec));
+
+ switch (oclass->codec->media_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (!force && marudec->format.video.width == marudec->context->video.width
+ && marudec->format.video.height == marudec->context->video.height
+ && marudec->format.video.fps_n == marudec->format.video.old_fps_n
+ && marudec->format.video.fps_d == marudec->format.video.old_fps_d
+ && marudec->format.video.pix_fmt == marudec->context->video.pix_fmt
+ && marudec->format.video.par_n == marudec->context->video.par_n
+ && marudec->format.video.par_d == marudec->context->video.par_d) {
+ return TRUE;
+ }
+ marudec->format.video.width = marudec->context->video.width;
+ marudec->format.video.height = marudec->context->video.height;
+ marudec->format.video.old_fps_n = marudec->format.video.fps_n;
+ marudec->format.video.old_fps_d = marudec->format.video.fps_d;
+ marudec->format.video.pix_fmt = marudec->context->video.pix_fmt;
+ marudec->format.video.par_n = marudec->context->video.par_n;
+ marudec->format.video.par_d = marudec->context->video.par_d;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ {
+ gint depth = gst_maru_smpfmt_depth (marudec->context->audio.sample_fmt);
+ if (!force && marudec->format.audio.samplerate ==
+ marudec->context->audio.sample_rate &&
+ marudec->format.audio.channels == marudec->context->audio.channels &&
+ marudec->format.audio.depth == depth) {
+ return TRUE;
+ }
+ marudec->format.audio.samplerate = marudec->context->audio.sample_rate;
+ marudec->format.audio.channels = marudec->context->audio.channels;
+ marudec->format.audio.depth = depth;
+ }
+ break;
+ default:
+ break;
+ }
+
+ caps =
+ gst_maru_codectype_to_caps (oclass->codec->media_type, marudec->context,
+ oclass->codec->name, FALSE);
+
+ if (caps == NULL) {
+ GST_ELEMENT_ERROR (marudec, 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 = marudec->format.video.clip_width;
+ height = marudec->format.video.clip_height;
+ interlaced = marudec->format.video.interlaced;
+
+ if (width != -1 && height != -1) {
+ if (width < marudec->context->video.width) {
+ gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL);
+ }
+ if (height < marudec->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 (marudec->format.video.fps_n != -1) {
+ gst_caps_set_simple (caps, "framerate",
+ GST_TYPE_FRACTION, marudec->format.video.fps_n,
+ marudec->format.video.fps_d, NULL);
+ }
+#if 0
+ gst_marudec_add_pixel_aspect_ratio (marudec,
+ gst_caps_get_structure (caps, 0));
+#endif
+ }
+ }
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ break;
+ default:
+ break;
+ }
+
+ if (!gst_pad_set_caps (marudec->srcpad, caps)) {
+ GST_ELEMENT_ERROR (marudec, 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 GstFlowReturn
+get_output_buffer (GstEmulDec *marudec, GstBuffer **outbuf)
+{
+ gint pict_size;
+ GstFlowReturn ret;
+
+ ret = GST_FLOW_OK;
+
+ *outbuf = NULL;
+
+ if (G_UNLIKELY (!gst_marudec_negotiate (marudec, FALSE))) {
+ GST_DEBUG_OBJECT (marudec, "negotiate failed");
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+
+ pict_size = gst_maru_avpicture_size (marudec->context->video.pix_fmt,
+ marudec->context->video.width, marudec->context->video.height);
+ if (pict_size < 0) {
+ GST_DEBUG_OBJECT (marudec, "size of a picture is negative. "
+ "pixel format: %d, width: %d, height: %d",
+ marudec->context->video.pix_fmt, marudec->context->video.width,
+ marudec->context->video.height);
+ return GST_FLOW_ERROR;
+ }
+
+ CODEC_LOG (DEBUG, "outbuf size of decoded video: %d\n", pict_size);
+
+ if (pict_size < (256 * 1024)) {
+ /* GstPadBufferAllocFunction is mostly overridden by elements that can
+ * provide a hardware buffer in order to avoid additional memcpy operations.
+ */
+ gst_pad_set_bufferalloc_function(
+ GST_PAD_PEER(marudec->srcpad),
+ (GstPadBufferAllocFunction) codec_buffer_alloc);
+ } else {
+ CODEC_LOG (DEBUG, "request a large size of memory\n");
+ }
+
+ ret = gst_pad_alloc_buffer_and_set_caps (marudec->srcpad,
+ GST_BUFFER_OFFSET_NONE, pict_size,
+ GST_PAD_CAPS (marudec->srcpad), outbuf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ GST_DEBUG_OBJECT (marudec, "pad_alloc failed %d (%s)", ret,
+ gst_flow_get_name (ret));
+ return ret;
+ }
+
+ if ((uintptr_t) GST_BUFFER_DATA (*outbuf) % 16) {
+ GST_DEBUG_OBJECT (marudec,
+ "Downstream can't allocate aligned buffers.");
+ gst_buffer_unref (*outbuf);
+ *outbuf = new_aligned_buffer (pict_size, GST_PAD_CAPS (marudec->srcpad));
+ }
+
+ codec_picture_copy (marudec->context, GST_BUFFER_DATA (*outbuf),
+ GST_BUFFER_SIZE (*outbuf), marudec->dev);
+
+ return ret;
+}
+
+static gboolean
+clip_video_buffer (GstEmulDec *dec, GstBuffer *buf,
+ GstClockTime in_ts, GstClockTime in_dur)
+{
+ gboolean res = TRUE;
+
+ return res;
+}
+
+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_marudec_video_frame (GstEmulDec *marudec, guint8 *data, guint size,
+ const GstTSInfo *dec_info, gint64 in_offset, GstBuffer **outbuf,
+ GstFlowReturn *ret)
+{
+ gint len = -1, have_data;
+ gboolean mode_switch;
+ gboolean decode;
+ GstClockTime out_timestamp, out_duration, out_pts;
+ gint64 out_offset;
+ const GstTSInfo *out_info;
+
+ decode = gst_marudec_do_qos (marudec, dec_info->timestamp, &mode_switch);
+
+ CODEC_LOG (DEBUG, "decode video: input buffer size: %d\n", size);
+ len =
+ codec_decode_video (marudec->context, data, size,
+ dec_info->idx, in_offset, outbuf,
+ &have_data, marudec->dev);
+
+ if (!decode) {
+ // skip_frame
+ }
+
+ GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
+ len, have_data);
+
+#if 0
+ if (len < 0 && (mode_switch || marudec->context->skip_frame)) {
+ len = 0;
+ }
+
+ if (len > 0 && have_data <= 0 && (mode_switch
+ || marudec->context->skip_frame)) {
+ marudec->last_out = -1;
+ }
+#endif
+
+ if (len < 0 || have_data <= 0) {
+ GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
+ *ret, *outbuf, len);
+ return len;
+ }
+
+ out_info = gst_ts_info_get (marudec, dec_info->idx);
+ out_pts = out_info->timestamp;
+ out_duration = out_info->duration;
+ out_offset = out_info->offset;
+
+ *ret = get_output_buffer (marudec, outbuf);
+ if (G_UNLIKELY (*ret != GST_FLOW_OK)) {
+ GST_DEBUG_OBJECT (marudec, "no output buffer");
+ len = -1;
+ GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
+ *ret, *outbuf, len);
+ return len;
+ }
+
+ /* Timestamps */
+ out_timestamp = -1;
+ if (out_pts != -1) {
+ out_timestamp = (GstClockTime) out_pts;
+ GST_LOG_OBJECT (marudec, "using timestamp %" GST_TIME_FORMAT
+ " returned by ffmpeg", GST_TIME_ARGS (out_timestamp));
+ }
+
+ if (!GST_CLOCK_TIME_IS_VALID (out_timestamp) && marudec->next_out != -1) {
+ out_timestamp = marudec->next_out;
+ GST_LOG_OBJECT (marudec, "using next timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (out_timestamp));
+ }
+
+ if (!GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
+ out_timestamp = dec_info->timestamp;
+ GST_LOG_OBJECT (marudec, "using in timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (out_timestamp));
+ }
+ GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp;
+
+ /* Offset */
+ if (out_offset != GST_BUFFER_OFFSET_NONE) {
+ GST_LOG_OBJECT (marudec, "Using offset returned by ffmpeg");
+ } else if (out_timestamp != GST_CLOCK_TIME_NONE) {
+ GstFormat out_fmt = GST_FORMAT_DEFAULT;
+ GST_LOG_OBJECT (marudec, "Using offset converted from timestamp");
+
+ gst_pad_query_peer_convert (marudec->sinkpad,
+ GST_FORMAT_TIME, out_timestamp, &out_fmt, &out_offset);
+ } else if (dec_info->offset != GST_BUFFER_OFFSET_NONE) {
+ GST_LOG_OBJECT (marudec, "using in_offset %" G_GINT64_FORMAT,
+ dec_info->offset);
+ out_offset = dec_info->offset;
+ } else {
+ GST_LOG_OBJECT (marudec, "no valid offset found");
+ out_offset = GST_BUFFER_OFFSET_NONE;
+ }
+ GST_BUFFER_OFFSET (*outbuf) = out_offset;
+
+ /* Duration */
+ if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
+ GST_LOG_OBJECT (marudec, "Using duration returned by ffmpeg");
+ } else if (GST_CLOCK_TIME_IS_VALID (dec_info->duration)) {
+ GST_LOG_OBJECT (marudec, "Using in_duration");
+ out_duration = dec_info->duration;
+#if 0
+ } else if (GST_CLOCK_TIME_IS_VALID (marudec->last_diff)) {
+ GST_LOG_OBJECT (marudec, "Using last-diff");
+ out_duration = marudec->last_diff;
+#endif
+ } else {
+ if (marudec->format.video.fps_n != -1 &&
+ (marudec->format.video.fps_n != 1000 &&
+ marudec->format.video.fps_d != 1)) {
+ GST_LOG_OBJECT (marudec, "using input framerate for duration");
+ out_duration = gst_util_uint64_scale_int (GST_SECOND,
+ marudec->format.video.fps_d, marudec->format.video.fps_n);
+ } else {
+ if (marudec->context->video.fps_n != 0 &&
+ (marudec->context->video.fps_d > 0 &&
+ marudec->context->video.fps_d < 1000)) {
+ GST_LOG_OBJECT (marudec, "using decoder's framerate for duration");
+ out_duration = gst_util_uint64_scale_int (GST_SECOND,
+ marudec->context->video.fps_n * 1,
+ marudec->context->video.fps_d);
+ } else {
+ GST_LOG_OBJECT (marudec, "no valid duration found");
+ }
+ }
+ }
+
+#if 0
+ if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
+ out_duration += out_duration * marudec->picture->repeat_pict / 2;
+ }
+ GST_BUFFER_DURATION (*outbuf) = out_duration;
+
+ if (out_timestamp != -1 && out_duration != -1 && out_duration != 0) {
+ marudec->next_out = out_timestamp + out_duration;
+ } else {
+ marudec->next_out = -1;
+ }
+#endif
+
+ if (G_UNLIKELY (!clip_video_buffer (marudec, *outbuf, out_timestamp,
+ out_duration))) {
+ GST_DEBUG_OBJECT (marudec, "buffer clipped");
+ gst_buffer_unref (*outbuf);
+ *outbuf = NULL;
+ GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
+ *ret, *outbuf, len);
+ return len;
+ }
+
+ GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
+ *ret, *outbuf, len);
+ return len;
+}
+
+static gint
+gst_marudec_audio_frame (GstEmulDec *marudec, 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 (marudec->srcpad));
+
+ CODEC_LOG (DEBUG, "decode audio, input buffer size: %d\n", size);
+
+ len = codec_decode_audio (marudec->context,
+ (int16_t *) GST_BUFFER_DATA (*outbuf), &have_data,
+ data, size, marudec->dev);
+
+ GST_DEBUG_OBJECT (marudec,
+ "Decode audio: len=%d, have_data=%d", len, have_data);
+
+ if (len >= 0 && have_data > 0) {
+ GST_DEBUG_OBJECT (marudec, "Creating output buffer");
+ if (!gst_marudec_negotiate (marudec, FALSE)) {
+ gst_buffer_unref (*outbuf);
+ *outbuf = NULL;
+ len = -1;
+ GST_DEBUG_OBJECT (marudec, "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 = marudec->next_out;
+ }
+
+ /* calculate based on number of samples */
+ out_duration = gst_util_uint64_scale (have_data, GST_SECOND,
+ marudec->format.audio.depth * marudec->format.audio.channels *
+ marudec->format.audio.samplerate);
+
+ out_offset = dec_info->offset;
+
+ GST_DEBUG_OBJECT (marudec,
+ "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 (marudec->srcpad));
+
+ if (GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
+ marudec->next_out = out_timestamp + out_duration;
+ }
+
+ if (G_UNLIKELY (!clip_audio_buffer (marudec, *outbuf,
+ out_timestamp, out_duration))) {
+ GST_DEBUG_OBJECT (marudec, "buffer_clipped");
+ gst_buffer_unref (*outbuf);
+ *outbuf = NULL;
+ GST_DEBUG_OBJECT (marudec, "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 (marudec, STREAM, DECODE, (NULL),
+ ("Decoding of AAC stream by FFMPEG failed."));
+ *ret = GST_FLOW_ERROR;
+ }
+
+ GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
+ *ret, *outbuf, len);
+ return len;
+}
+
+static gint
+gst_marudec_frame (GstEmulDec *marudec, guint8 *data, guint size,
+ gint *got_data, const GstTSInfo *dec_info, gint64 in_offset, GstFlowReturn *ret)
+{
+ GstEmulDecClass *oclass;
+ GstBuffer *outbuf = NULL;
+ gint have_data = 0, len = 0;
+
+ if (G_UNLIKELY (marudec->context->codec == NULL)) {
+ GST_ERROR_OBJECT (marudec, "no codec context");
+ return -1;
+ }
+
+ *ret = GST_FLOW_OK;
+ oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (marudec));
+
+ switch (oclass->codec->media_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ len = gst_marudec_video_frame (marudec, data, size,
+ dec_info, in_offset, &outbuf, ret);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ len = gst_marudec_audio_frame (marudec, oclass->codec, data, size,
+ dec_info, &outbuf, ret);
+ if (outbuf == NULL && marudec->discont) {
+ GST_DEBUG_OBJECT (marudec, "no buffer but keeping timestamp");
+// marudec->clear_ts = FALSE;
+ }
+ break;
+ default:
+ GST_ERROR_OBJECT (marudec, "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 (marudec,
+ "maru_%sdec: 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 (marudec,
+ "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 (marudec->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);
+ marudec->discont = FALSE;
+ }
+
+ if (marudec->segment.rate > 0.0) {
+ // push forward
+ *ret = gst_pad_push (marudec->srcpad, outbuf);
+ } else {
+ // push reverse
+ GST_DEBUG_OBJECT (marudec, "queued frame");
+ marudec->queued = g_list_prepend (marudec->queued, outbuf);
+ *ret = GST_FLOW_OK;
+ }
+ } else {
+ GST_DEBUG_OBJECT (marudec, "Didn't get a decoded buffer");
+ }
+
+ return len;
+}
+
+static GstFlowReturn
+gst_marudec_chain (GstPad *pad, GstBuffer *buffer)
+{
+ GstEmulDec *marudec;
+ GstEmulDecClass *oclass;
+ guint8 *in_buf;
+ gint 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;
+
+ marudec = (GstEmulDec *) (GST_PAD_PARENT (pad));
+
+ if (G_UNLIKELY (!marudec->opened)) {
+ // not_negotiated
+ oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (marudec));
+ GST_ELEMENT_ERROR (marudec, CORE, NEGOTIATION, (NULL),
+ ("maru_%sdec: input format was not set before data start",
+ oclass->codec->name));
+ gst_buffer_unref (buffer);
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+
+ discont = GST_BUFFER_IS_DISCONT (buffer);
+
+// FIXME
+ if (G_UNLIKELY (discont)) {
+ GST_DEBUG_OBJECT (marudec, "received DISCONT");
+ gst_marudec_drain (marudec);
+// gst_marudec_flush_pcache (marudec);
+// maru_avcodec_flush buffers (marudec->context, marudec->dev);
+ marudec->discont = TRUE;
+ gst_marudec_reset_ts (marudec);
+ }
+// marudec->clear_ts = TRUE;
+
+ oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (marudec));
+#if 0
+ if (G_UNLIKELY (marudec->waiting_for_key)) {
+ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT) &&
+ oclass->codec->media_type != AVMEDIA_TYPE_AUDIO) {
+ // skip_keyframe
+ }
+ marudec->waiting_for_key = FALSE;
+ }
+
+ if (marudec->pcache) {
+ GST_LOG_OBJECT (marudec, "join parse cache");
+ buffer = gst_buffer_join (marudec->pcache, buffer);
+ marudec->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 (marudec, in_timestamp, in_duration, in_offset);
+
+#if 0
+ if (in_timestamp != -1) {
+ if (!marudec->reordered_in && marudec->last_in != -1) {
+ if (in_timestamp < marudec->last_in) {
+ GST_LOG_OBJECT (marudec, "detected reordered input timestamps");
+ marudec->reordered_in = TRUE;
+ marudec->last_diff = GST_CLOCK_TIME_NONE;
+ } else if (in_timestamp > marudec->last_in) {
+ GstClockTime diff;
+ diff = in_timestamp - marudec->last_in;
+ if (marudec->last_frames) {
+ diff /= marudec->last_frames;
+ }
+
+ GST_LOG_OBJECT (marudec, "estimated duration %" GST_TIME_FORMAT " %u",
+ GST_TIME_ARGS (diff), marudec->last_frames);
+
+ marudec->last_diff = diff;
+ }
+ }
+ marudec->last_in = in_timestamp;
+ marudec->last_frames;
+ }
+#endif
+
+ GST_LOG_OBJECT (marudec,
+ "Received new data of size %u, offset: %" G_GUINT64_FORMAT ", ts:%"
+ GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT ", info %d",
+ GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer),
+ GST_TIME_ARGS (in_timestamp), GST_TIME_ARGS (in_duration), in_info->idx);
+
+ in_buf = GST_BUFFER_DATA (buffer);
+ in_size = GST_BUFFER_SIZE (buffer);
+
+ dec_info = in_info;
+
+ len =
+ gst_marudec_frame (marudec, in_buf, in_size, &have_data, dec_info, in_offset, &ret);
+
+#if 0
+ if (marudec->clear_ts) {
+ in_timestamp = GST_CLOCK_TIME_NONE;
+ in_duration = GST_CLOCK_TIME_NONE;
+ in_offset = GST_BUFFER_OFFSET_NONE;
+ in_info = GST_TS_INFO_NONE;
+ } else {
+ marudec->clear_ts = TRUE;
+ }
+#endif
+
+ gst_buffer_unref (buffer);
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_marudec_change_state (GstElement *element, GstStateChange transition)
+{
+ GstEmulDec *marudec = (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 (marudec);
+ gst_marudec_close (marudec);
+ GST_OBJECT_UNLOCK (marudec);
+
+ /* clear queue */
+ clear_queued (marudec);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_marudec_register (GstPlugin *plugin, GList *element)
+{
+ GTypeInfo typeinfo = {
+ sizeof (GstEmulDecClass),
+ (GBaseInitFunc) gst_marudec_base_init,
+ NULL,
+ (GClassInitFunc) gst_marudec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstEmulDec),
+ 0,
+ (GInstanceInitFunc) gst_marudec_init,
+ };
+
+ GType type;
+ gchar *type_name;
+ gint rank = GST_RANK_PRIMARY;
+ GList *elem = element;
+ CodecElement *codec = NULL;
+
+ if (!elem) {
+ return FALSE;
+ }
+
+ /* register element */
+ do {
+ codec = (CodecElement *)(elem->data);
+ if (!codec) {
+ return FALSE;
+ }
+
+ if (codec->codec_type != CODEC_TYPE_DECODE) {
+ continue;
+ }
+
+ type_name = g_strdup_printf ("maru_%sdec", 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_MARUDEC_PARAMS_QDATA, (gpointer) codec);
+ }
+
+ if (!gst_element_register (plugin, type_name, rank, type)) {
+ g_free (type_name);
+ return FALSE;
+ }
+ g_free (type_name);
+ } while ((elem = elem->next));
+
+ return TRUE;
+}
--- /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 <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "gstmaruinterface.h"
+#include "gstmarudevice.h"
+
+static GStaticMutex gst_avcodec_mutex = G_STATIC_MUTEX_INIT;
+
+#define CODEC_DEVICE_MEM_SIZE 32 * 1024 * 1024
+
+gpointer device_mem;
+int device_fd;
+
+int
+gst_maru_codec_device_open (CodecDevice *dev, int media_type)
+{
+ int fd;
+ void *mmapbuf;
+
+ CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+ CODEC_LOG (INFO, "before opening a device. %d\n", dev->fd);
+ if ((fd = open(CODEC_DEV, O_RDWR)) < 0) {
+ perror("Failed to open codec device.");
+ return -1;
+ }
+ dev->fd = fd;
+
+// GST_DEBUG("succeeded to open %s. %d.\n", CODEC_DEV, fd);
+ CODEC_LOG (INFO, "succeeded to open %s. %d.\n", CODEC_DEV, fd);
+ dev->mem_info.index = dev->buf_size;
+
+ CODEC_LOG (DEBUG, "before mmap. buf_size: %d\n", dev->buf_size);
+ mmapbuf = mmap (NULL, CODEC_DEVICE_MEM_SIZE, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (mmapbuf == MAP_FAILED) {
+ perror("Failed to map device memory of codec.");
+ dev->buf = NULL;
+ return -1;
+ }
+
+// GST_DEBUG("succeeded to map device memory.\n");
+ CODEC_LOG (INFO, "succeeded to map device memory: %p.\n", mmapbuf);
+ dev->fd = fd;
+ dev->buf = mmapbuf;
+
+ if (media_type == AVMEDIA_TYPE_VIDEO) {
+ device_mem = mmapbuf;
+ device_fd = fd;
+ CODEC_LOG (INFO, "video type! mmapbuf: %p fd: %d\n", mmapbuf, fd);
+ }
+#if 0
+ else {
+ CODEC_LOG (INFO, "don't need to set device_mem because media type is not video. %d\n", media_type);
+ }
+#endif
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return 0;
+}
+
+int
+gst_maru_codec_device_close (CodecDevice *dev)
+{
+ int fd = 0;
+ void *mmapbuf = NULL;
+
+ CODEC_LOG (DEBUG, "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;
+ }
+
+ CODEC_LOG (INFO, "Release memory region of %p.\n", mmapbuf);
+ if (munmap(mmapbuf, CODEC_DEVICE_MEM_SIZE) != 0) {
+ CODEC_LOG(ERR, "Failed to release memory region of %s.\n", CODEC_DEV);
+ }
+ dev->buf = NULL;
+
+ ioctl(fd, CODEC_CMD_RELEASE_BUFFER, &dev->mem_info.offset);
+
+ CODEC_LOG (INFO, "close %s.\n", CODEC_DEV);
+ if (close(fd) != 0) {
+ GST_ERROR("Failed to close %s. fd: %d\n", CODEC_DEV, fd);
+ }
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return 0;
+}
+
+int
+gst_maru_avcodec_open (CodecContext *ctx,
+ CodecElement *codec,
+ CodecDevice *dev)
+{
+ int ret;
+
+ g_static_mutex_lock (&gst_avcodec_mutex);
+
+ if (gst_maru_codec_device_open (dev, codec->media_type) < 0) {
+ perror("failed to open device.\n");
+ return -1;
+ }
+ ret = codec_init (ctx, codec, dev);
+ g_static_mutex_unlock (&gst_avcodec_mutex);
+
+ return ret;
+}
+
+int
+gst_maru_avcodec_close (CodecContext *ctx, CodecDevice *dev)
+{
+ int ret;
+
+ g_static_mutex_lock (&gst_avcodec_mutex);
+
+ CODEC_LOG (DEBUG, "gst_maru_avcodec_close\n");
+ codec_deinit (ctx, dev);
+
+ ret = gst_maru_codec_device_close (dev);
+ g_static_mutex_unlock (&gst_avcodec_mutex);
+
+ 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
+ *
+ */
+
+#ifndef __GST_MARU_DEVICE_H__
+#define __GST_MARU_DEVICE_H__
+
+int gst_emul_codec_device_open (CodecDevice *dev, int media_type);
+int gst_emul_codec_device_close (CodecDevice *dev);
+
+int gst_emul_avcodec_open (CodecContext *ctx,
+ CodecElement *codec,
+ CodecDevice *dev);
+int gst_emul_avcodec_close (CodecContext *ctx, 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 "gstmaruutils.h"
+#include "gstmaruinterface.h"
+#include "gstmarudevice.h"
+#include <gst/base/gstadapter.h>
+
+#define GST_MARUENC_PARAMS_QDATA g_quark_from_static_string("maruenc-params")
+
+typedef struct _GstEmulEnc
+{
+ GstElement element;
+
+ GstPad *srcpad;
+ GstPad *sinkpad;
+
+ CodecContext *context;
+ CodecDevice *dev;
+ gboolean opened;
+ GstClockTime adapter_ts;
+ guint64 adapter_consumed;
+ GstAdapter *adapter;
+ gboolean discont;
+
+ // cache
+ gulong bitrate;
+ gint gop_size;
+ gulong buffer_size;
+
+ guint8 *working_buf;
+ gulong working_buf_size;
+
+ GQueue *delay;
+
+} GstEmulEnc;
+
+typedef struct _GstEmulEncClass
+{
+ GstElementClass parent_class;
+
+ CodecElement *codec;
+ GstPadTemplate *sinktempl;
+ GstPadTemplate *srctempl;
+ GstCaps *sinkcaps;
+} GstEmulEncClass;
+
+static GstElementClass *parent_class = NULL;
+
+static void gst_maruenc_base_init (GstEmulEncClass *klass);
+static void gst_maruenc_class_init (GstEmulEncClass *klass);
+static void gst_maruenc_init (GstEmulEnc *maruenc);
+static void gst_maruenc_finalize (GObject *object);
+
+static gboolean gst_maruenc_setcaps (GstPad *pad, GstCaps *caps);
+static GstCaps *gst_maruenc_getcaps (GstPad *pad);
+
+static GstCaps *gst_maruenc_get_possible_sizes (GstEmulEnc *maruenc,
+ GstPad *pad, const GstCaps *caps);
+
+static GstFlowReturn gst_maruenc_chain_video (GstPad *pad, GstBuffer *buffer);
+static GstFlowReturn gst_maruenc_chain_audio (GstPad *pad, GstBuffer *buffer);
+
+static gboolean gst_maruenc_event_video (GstPad *pad, GstEvent *event);
+static gboolean gst_maruenc_event_src (GstPad *pad, GstEvent *event);
+
+GstStateChangeReturn gst_maruenc_change_state (GstElement *element, GstStateChange transition);
+
+#define DEFAULT_VIDEO_BITRATE 300000
+#define DEFAULT_VIDEO_GOP_SIZE 15
+#define DEFAULT_AUDIO_BITRATE 128000
+
+#define DEFAULT_WIDTH 352
+#define DEFAULT_HEIGHT 288
+
+/*
+ * Implementation
+ */
+static void
+gst_maruenc_base_init (GstEmulEncClass *klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstPadTemplate *sinktempl = NULL, *srctempl = NULL;
+ GstCaps *sinkcaps = NULL, *srccaps = NULL;
+ CodecElement *codec;
+ gchar *longname, *classification, *description;
+
+ codec =
+ (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
+ GST_MARUENC_PARAMS_QDATA);
+
+ longname = g_strdup_printf ("%s Encoder", codec->longname);
+ classification = g_strdup_printf ("Codec/Encoder/%s",
+ (codec->media_type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio");
+ description = g_strdup_printf ("%s Encoder", codec->name);
+
+ gst_element_class_set_details_simple (element_class,
+ longname,
+ classification,
+ description,
+// "accelerated codec for Tizen Emulator",
+ "Kitae Kim <kt920.kim@samsung.com>");
+
+ g_free (longname);
+ g_free (classification);
+
+
+ if (!(srccaps = gst_maru_codecname_to_caps (codec->name, NULL, TRUE))) {
+ GST_DEBUG ("Couldn't get source caps for encoder '%s'", codec->name);
+ srccaps = gst_caps_new_simple ("unknown/unknown", NULL);
+ }
+
+ switch (codec->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:
+ sinkcaps = gst_maru_codectype_to_audio_caps (NULL, codec->name, TRUE, codec);
+ break;
+ default:
+ GST_LOG("unknown media type.\n");
+ break;
+ }
+
+ if (!sinkcaps) {
+ GST_DEBUG ("Couldn't get sink caps for encoder '%s'", 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->codec = codec;
+ klass->sinktempl = sinktempl;
+ klass->srctempl = srctempl;
+ klass->sinkcaps = NULL;
+}
+
+static void
+gst_maruenc_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_maruenc_set_property
+ gobject_class->get_property = gst_maruenc_get_property
+#endif
+
+ gstelement_class->change_state = gst_maruenc_change_state;
+
+ gobject_class->finalize = gst_maruenc_finalize;
+}
+
+static void
+gst_maruenc_init (GstEmulEnc *maruenc)
+{
+ GstEmulEncClass *oclass;
+ oclass = (GstEmulEncClass*) (G_OBJECT_GET_CLASS(maruenc));
+
+ maruenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
+ gst_pad_set_setcaps_function (maruenc->sinkpad,
+ GST_DEBUG_FUNCPTR(gst_maruenc_setcaps));
+ gst_pad_set_getcaps_function (maruenc->sinkpad,
+ GST_DEBUG_FUNCPTR(gst_maruenc_getcaps));
+
+ maruenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
+ gst_pad_use_fixed_caps (maruenc->srcpad);
+
+ if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO) {
+ gst_pad_set_chain_function (maruenc->sinkpad, gst_maruenc_chain_video);
+ gst_pad_set_event_function (maruenc->sinkpad, gst_maruenc_event_video);
+ gst_pad_set_event_function (maruenc->srcpad, gst_maruenc_event_src);
+
+ maruenc->bitrate = DEFAULT_VIDEO_BITRATE;
+ maruenc->buffer_size = 512 * 1024;
+ maruenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
+#if 0
+ maruenc->lmin = 2;
+ maruenc->lmax = 31;
+#endif
+ } else if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO){
+ gst_pad_set_chain_function (maruenc->sinkpad, gst_maruenc_chain_audio);
+ maruenc->bitrate = DEFAULT_AUDIO_BITRATE;
+ }
+
+ gst_element_add_pad (GST_ELEMENT (maruenc), maruenc->sinkpad);
+ gst_element_add_pad (GST_ELEMENT (maruenc), maruenc->srcpad);
+
+ maruenc->context = g_malloc0 (sizeof(CodecContext));
+ maruenc->context->video.pix_fmt = PIX_FMT_NONE;
+ maruenc->context->audio.sample_fmt = SAMPLE_FMT_NONE;
+
+ maruenc->opened = FALSE;
+
+#if 0
+ maruenc->file = NULL;
+#endif
+ maruenc->delay = g_queue_new ();
+
+ maruenc->dev = g_malloc0 (sizeof(CodecDevice));
+ if (!maruenc->dev) {
+ printf("[gst-maru][%d] failed to allocate memory\n", __LINE__);
+ }
+
+ // need to know what adapter does.
+ maruenc->adapter = gst_adapter_new ();
+}
+
+static void
+gst_maruenc_finalize (GObject *object)
+{
+ // Deinit Decoder
+ GstEmulEnc *maruenc = (GstEmulEnc *) object;
+
+ if (maruenc->opened) {
+ gst_maru_avcodec_close (maruenc->context, maruenc->dev);
+ maruenc->opened = FALSE;
+ }
+
+ if (maruenc->context) {
+ g_free (maruenc->context);
+ maruenc->context = NULL;
+ }
+
+ g_queue_free (maruenc->delay);
+#if 0
+ g_free (maruenc->filename);
+#endif
+
+ g_object_unref (maruenc->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_maruenc_get_possible_sizes (GstEmulEnc *maruenc, GstPad *pad,
+ const GstCaps *caps)
+{
+ GstCaps *othercaps = NULL;
+ GstCaps *tmpcaps = NULL;
+ GstCaps *intersect = NULL;
+ guint i;
+
+ othercaps = gst_pad_peer_get_caps (maruenc->srcpad);
+
+ if (!othercaps) {
+ return gst_caps_copy (caps);
+ }
+
+ intersect = gst_caps_intersect (othercaps,
+ gst_pad_get_pad_template_caps (maruenc->srcpad));
+ gst_caps_unref (othercaps);
+
+ if (gst_caps_is_empty (intersect)) {
+ return intersect;
+ }
+
+ if (gst_caps_is_any (intersect)) {
+ return gst_caps_copy (caps);
+ }
+
+ tmpcaps = gst_caps_new_empty ();
+
+ for (i = 0; i <gst_caps_get_size (intersect); i++) {
+ GstStructure *s = gst_caps_get_structure (intersect, i);
+ const GValue *height = NULL;
+ const GValue *width = NULL;
+ const GValue *framerate = NULL;
+ GstStructure *tmps;
+
+ height = gst_structure_get_value (s, "height");
+ width = gst_structure_get_value (s, "width");
+ framerate = gst_structure_get_value (s, "framerate");
+
+ tmps = gst_structure_new ("video/x-rwa-rgb", NULL);
+ if (width) {
+ gst_structure_set_value (tmps, "width", width);
+ }
+ if (height) {
+ gst_structure_set_value (tmps, "height", height);
+ }
+ if (framerate) {
+ gst_structure_set_value (tmps, "framerate", framerate);
+ }
+ gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
+
+ gst_structure_set_name (tmps, "video/x-raw-yuv");
+ gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
+
+ gst_structure_set_name (tmps, "video/x-raw-gray");
+ gst_caps_merge_structure (tmpcaps, tmps);
+ }
+ gst_caps_unref (intersect);
+
+ intersect = gst_caps_intersect (caps, tmpcaps);
+ gst_caps_unref (tmpcaps);
+
+ return intersect;
+}
+
+static GstCaps *
+gst_maruenc_getcaps (GstPad *pad)
+{
+ GstEmulEnc *maruenc = (GstEmulEnc *) GST_PAD_PARENT (pad);
+ GstEmulEncClass *oclass =
+ (GstEmulEncClass *) G_OBJECT_GET_CLASS (maruenc);
+ CodecContext *ctx = NULL;
+ enum PixelFormat pixfmt;
+ GstCaps *caps = NULL;
+ GstCaps *finalcaps = NULL;
+ gint i;
+
+ GST_DEBUG_OBJECT (maruenc, "getting caps");
+
+ if (!oclass->codec) {
+ GST_ERROR_OBJECT (maruenc, "codec element is null.");
+ return NULL;
+ }
+
+ if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO) {
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+
+ GST_DEBUG_OBJECT (maruenc, "audio caps, return template %" GST_PTR_FORMAT,
+ caps);
+ return caps;
+ }
+
+ // cached
+ if (oclass->sinkcaps) {
+ caps = gst_maruenc_get_possible_sizes (maruenc, pad, oclass->sinkcaps);
+ GST_DEBUG_OBJECT (maruenc, "return cached caps %" GST_PTR_FORMAT, caps);
+ return caps;
+ }
+
+ GST_DEBUG_OBJECT (maruenc, "probing caps");
+ i = pixfmt = 0;
+
+ for (pixfmt = 0;; pixfmt++) {
+ GstCaps *tmpcaps;
+
+ if ((pixfmt = oclass->codec->pix_fmts[i++]) == PIX_FMT_NONE) {
+ GST_DEBUG_OBJECT (maruenc,
+ "At the end of official pixfmt for this codec, breaking out");
+ break;
+ }
+
+ GST_DEBUG_OBJECT (maruenc,
+ "Got an official pixfmt [%d], attempting to get caps", pixfmt);
+ tmpcaps = gst_maru_pixfmt_to_caps (pixfmt, NULL, oclass->codec->name);
+ if (tmpcaps) {
+ GST_DEBUG_OBJECT (maruenc, "Got caps, breaking out");
+ if (!caps) {
+ caps = gst_caps_new_empty ();
+ }
+ gst_caps_append (caps, tmpcaps);
+ continue;
+ }
+
+ GST_DEBUG_OBJECT (maruenc,
+ "Couldn't figure out caps without context, trying again with a context");
+
+ GST_DEBUG_OBJECT (maruenc, "pixfmt: %d", pixfmt);
+ if (pixfmt >= PIX_FMT_NB) {
+ GST_WARNING ("Invalid pixfmt, breaking out");
+ break;
+ }
+
+ ctx = g_malloc0 (sizeof(CodecContext));
+ if (!ctx) {
+ GST_DEBUG_OBJECT (maruenc, "no context");
+ break;
+ }
+
+ ctx->video.width = DEFAULT_WIDTH;
+ ctx->video.height = DEFAULT_HEIGHT;
+ ctx->video.fps_n = 1;
+ ctx->video.fps_d = 25;
+ ctx->video.ticks_per_frame = 1;
+ ctx->bit_rate = DEFAULT_VIDEO_BITRATE;
+
+// ctx->strict_std_compliance = -1;
+ ctx->video.pix_fmt = pixfmt;
+
+ GST_DEBUG ("Attempting to open codec");
+ if (gst_maru_avcodec_open (ctx, oclass->codec, maruenc->dev) >= 0
+ && ctx->video.pix_fmt == pixfmt) {
+ ctx->video.width = -1;
+ if (!caps) {
+ caps = gst_caps_new_empty ();
+ }
+ tmpcaps = gst_maru_codectype_to_caps (oclass->codec->media_type, ctx,
+ oclass->codec->name, TRUE);
+ if (tmpcaps) {
+ gst_caps_append (caps, tmpcaps);
+ } else {
+ GST_LOG_OBJECT (maruenc,
+ "Couldn't get caps for codec: %s", oclass->codec->name);
+ }
+ gst_maru_avcodec_close (ctx, maruenc->dev);
+ } else {
+ GST_DEBUG_OBJECT (maruenc, "Opening codec failed with pixfmt: %d", pixfmt);
+ }
+
+ gst_maru_avcodec_close (ctx, maruenc->dev);
+#if 0
+ if (ctx->priv_data) {
+ gst_maru_avcodec_close (ctx, maruenc->dev);
+ }
+#endif
+ g_free (ctx);
+ }
+
+ if (!caps) {
+ caps = gst_maruenc_get_possible_sizes (maruenc, pad,
+ gst_pad_get_pad_template_caps (pad));
+ GST_DEBUG_OBJECT (maruenc, "probing gave nothing, "
+ "return template %" GST_PTR_FORMAT, caps);
+ return caps;
+ }
+
+ GST_DEBUG_OBJECT (maruenc, "probed caps gave %" GST_PTR_FORMAT, caps);
+ oclass->sinkcaps = gst_caps_copy (caps);
+
+ finalcaps = gst_maruenc_get_possible_sizes (maruenc, pad, caps);
+ gst_caps_unref (caps);
+
+ return finalcaps;
+}
+
+static gboolean
+gst_maruenc_setcaps (GstPad *pad, GstCaps *caps)
+{
+ GstEmulEnc *maruenc;
+ GstEmulEncClass *oclass;
+ GstCaps *other_caps;
+ GstCaps *allowed_caps;
+ GstCaps *icaps;
+ enum PixelFormat pix_fmt;
+ int32_t buf_size;
+
+ maruenc = (GstEmulEnc *) (gst_pad_get_parent (pad));
+ oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (maruenc));
+
+ if (maruenc->opened) {
+ gst_maru_avcodec_close (maruenc->context, maruenc->dev);
+ maruenc->opened = FALSE;
+
+ gst_pad_set_caps (maruenc->srcpad, NULL);
+ }
+
+ maruenc->context->bit_rate = maruenc->bitrate;
+ GST_DEBUG_OBJECT (maruenc, "Setting context to bitrate %lu, gop_size %d",
+ maruenc->bitrate, maruenc->gop_size);
+
+#if 0
+
+ // user defined properties
+ maruenc->context->gop_size = maruenc->gop_size;
+ maruenc->context->lmin = (maruenc->lmin * FF_QP2LAMBDA + 0.5);
+ maruenc->context->lmax = (maruenc->lmax * FF_QP2LAMBDA + 0.5);
+
+ // some other defaults
+ maruenc->context->b_frame_strategy = 0;
+ maruenc->context->coder_type = 0;
+ maruenc->context->context_model = 0;
+ maruenc->context->scenechange_threshold = 0;
+ maruenc->context->inter_threshold = 0;
+
+ if (maruenc->interlaced) {
+ maruenc->context->flags |=
+ CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
+ maruenc->picture->interlaced_frame = TRUE;
+
+ maruenc->picture->top_field_first = TRUE;
+ }
+#endif
+
+ gst_maru_caps_with_codectype (oclass->codec->media_type, caps, maruenc->context);
+
+ if (!maruenc->context->video.fps_d) {
+ maruenc->context->video.fps_d = 25;
+ maruenc->context->video.fps_n = 1;
+ } else if (!strcmp(oclass->codec->name ,"mpeg4")
+ && (maruenc->context->video.fps_d > 65535)) {
+ maruenc->context->video.fps_n =
+ (gint) gst_util_uint64_scale_int (maruenc->context->video.fps_n,
+ 65535, maruenc->context->video.fps_d);
+ maruenc->context->video.fps_d = 65535;
+ GST_LOG_OBJECT (maruenc, "MPEG4 : scaled down framerate to %d / %d",
+ maruenc->context->video.fps_d, maruenc->context->video.fps_n);
+ }
+
+ pix_fmt = maruenc->context->video.pix_fmt;
+
+ {
+ switch (oclass->codec->media_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ {
+ int width, height;
+
+ width = maruenc->context->video.width;
+ height = maruenc->context->video.height;
+ buf_size = width * height * 6 + FF_MIN_BUFFER_SIZE + 100;
+ break;
+ }
+ case AVMEDIA_TYPE_AUDIO:
+ buf_size = FF_MAX_AUDIO_FRAME_SIZE + 100;
+ break;
+ default:
+ buf_size = -1;
+ break;
+ }
+ }
+
+ maruenc->dev->buf_size = gst_maru_align_size(buf_size);
+
+ // open codec
+ if (gst_maru_avcodec_open (maruenc->context,
+ oclass->codec, maruenc->dev) < 0) {
+ GST_DEBUG_OBJECT (maruenc, "maru_%senc: Failed to open codec",
+ oclass->codec->name);
+ return FALSE;
+ }
+
+ if (pix_fmt != maruenc->context->video.pix_fmt) {
+ gst_maru_avcodec_close (maruenc->context, maruenc->dev);
+ GST_DEBUG_OBJECT (maruenc,
+ "maru_%senc: AV wants different colorspace (%d given, %d wanted)",
+ oclass->codec->name, pix_fmt, maruenc->context->video.pix_fmt);
+ return FALSE;
+ }
+
+ if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO
+ && pix_fmt == PIX_FMT_NONE) {
+ GST_DEBUG_OBJECT (maruenc, "maru_%senc: Failed to determine input format",
+ oclass->codec->name);
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT (maruenc, "picking an output format.");
+ allowed_caps = gst_pad_get_allowed_caps (maruenc->srcpad);
+ if (!allowed_caps) {
+ GST_DEBUG_OBJECT (maruenc, "but no peer, using template caps");
+ allowed_caps =
+ gst_caps_copy (gst_pad_get_pad_template_caps (maruenc->srcpad));
+ }
+
+ GST_DEBUG_OBJECT (maruenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
+ gst_maru_caps_with_codecname (oclass->codec->name,
+ oclass->codec->media_type, allowed_caps, maruenc->context);
+
+ other_caps =
+ gst_maru_codecname_to_caps (oclass->codec->name, maruenc->context, TRUE);
+ if (!other_caps) {
+ GST_DEBUG("Unsupported codec - no caps found");
+ gst_maru_avcodec_close (maruenc->context, maruenc->dev);
+ 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);
+ gst_caps_unref (icaps);
+ icaps = newcaps;
+ }
+
+ if (!gst_pad_set_caps (maruenc->srcpad, icaps)) {
+ gst_maru_avcodec_close (maruenc->context, maruenc->dev);
+ gst_caps_unref (icaps);
+ return FALSE;
+ }
+ gst_object_unref (maruenc);
+
+ maruenc->opened = TRUE;
+
+ return TRUE;
+}
+
+static void
+gst_maruenc_setup_working_buf (GstEmulEnc *maruenc)
+{
+ guint wanted_size =
+ maruenc->context->video.width * maruenc->context->video.height * 6 +
+ FF_MIN_BUFFER_SIZE;
+
+ if (maruenc->working_buf == NULL ||
+ maruenc->working_buf_size != wanted_size) {
+ if (maruenc->working_buf) {
+ g_free (maruenc->working_buf);
+ }
+ maruenc->working_buf_size = wanted_size;
+ maruenc->working_buf = g_malloc0 (maruenc->working_buf_size);
+ }
+ maruenc->buffer_size = wanted_size;
+}
+
+GstFlowReturn
+gst_maruenc_chain_video (GstPad *pad, GstBuffer *buffer)
+{
+ GstEmulEnc *maruenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
+ GstBuffer *outbuf;
+ gint ret_size = 0, frame_size;
+
+ GST_DEBUG_OBJECT (maruenc,
+ "Received buffer of time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+
+#if 0
+ GST_OBJECT_LOCK (maruenc);
+ force_keyframe = maruenc->force_keyframe;
+ maruenc->force_keyframe = FALSE;
+ GST_OBJECT_UNLOCK (maruenc);
+
+ if (force_keyframe) {
+ maruenc->picture->pict_type = FF_I_TYPE;
+ }
+#endif
+
+ frame_size = gst_maru_avpicture_size (maruenc->context->video.pix_fmt,
+ maruenc->context->video.width, maruenc->context->video.height);
+ g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (buffer),
+ GST_FLOW_ERROR);
+
+#if 0
+ pts = gst_maru_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buffer) /
+ maruenc->context.video.ticks_per_frame,
+ maruenc->context.video.fps_n, maruen->context.video.fps_d);
+#endif
+
+ // TODO: check whether this func needs or not.
+ gst_maruenc_setup_working_buf (maruenc);
+
+ ret_size =
+ codec_encode_video (maruenc->context, maruenc->working_buf,
+ maruenc->working_buf_size, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer), GST_BUFFER_TIMESTAMP (buffer),
+ maruenc->dev);
+
+ if (ret_size < 0) {
+ GstEmulEncClass *oclass =
+ (GstEmulEncClass *) (G_OBJECT_GET_CLASS (maruenc));
+ GST_ERROR_OBJECT (maruenc,
+ "maru_%senc: failed to encode buffer", oclass->codec->name);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+
+ g_queue_push_tail (maruenc->delay, buffer);
+ if (ret_size) {
+ buffer = g_queue_pop_head (maruenc->delay);
+ } else {
+ return GST_FLOW_OK;
+ }
+
+#if 0
+ if (maruenc->file && maruenc->context->stats_out) {
+ if (fprintf (maruenc->file, "%s", maruenc->context->stats_out) < 0) {
+ GST_ELEMENT_ERROR (maruenc, RESOURCE, WRITE,
+ (("Could not write to file \"%s\"."), maruenc->filename),
+ GST_ERROR_SYSTEM);
+ }
+ }
+#endif
+#if 1
+ {
+ int ret;
+ uint32_t mem_offset;
+ uint8_t *working_buf = NULL;
+
+ mem_offset = maruenc->dev->mem_info.offset;
+ working_buf = maruenc->dev->buf + mem_offset;
+ if (!working_buf) {
+ } else {
+ CODEC_LOG (INFO,
+ "encoded video. mem_offset = 0x%x\n", mem_offset);
+
+ outbuf = gst_buffer_new_and_alloc (ret_size);
+// memcpy (GST_BUFFER_DATA (outbuf), maruenc->working_buf, ret_size);
+ memcpy (GST_BUFFER_DATA (outbuf), working_buf, ret_size);
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
+ GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
+ }
+
+ ret = ioctl(maruenc->dev->fd, CODEC_CMD_RELEASE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed to release used buffer\n");
+ }
+ }
+#endif
+
+#if 0
+ if (maruenc->context->coded_frame) {
+ if (!maruenc->context->coded_frame->key_frame) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+ } else {
+ GST_WARNING_OBJECT (maruenc, "codec did not provide keyframe info");
+ }
+#endif
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (maruenc->srcpad));
+
+ gst_buffer_unref (buffer);
+
+#if 0
+
+ if (force_keyframe) {
+ gst_pad_push_event (maruenc->srcpad,
+ gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
+ gst_structure_new ("GstForceKeyUnit", "timestamp",
+ G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), NULL)));
+ }
+#endif
+
+ return gst_pad_push (maruenc->srcpad, outbuf);
+}
+
+GstFlowReturn
+gst_maruenc_encode_audio (GstEmulEnc *maruenc, guint8 *audio_in,
+ guint in_size, guint max_size, GstClockTime timestamp,
+ GstClockTime duration, gboolean discont)
+{
+ GstBuffer *outbuf;
+ guint8 *audio_out;
+ gint res;
+ GstFlowReturn ret;
+
+ outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE);
+ audio_out = GST_BUFFER_DATA (outbuf);
+
+ GST_LOG_OBJECT (maruenc, "encoding buffer of max size %d", max_size);
+ if (maruenc->buffer_size != max_size) {
+ maruenc->buffer_size = max_size;
+ }
+
+ res = codec_encode_audio (maruenc->context, audio_out, max_size,
+ audio_in, in_size, maruenc->dev);
+
+ if (res < 0) {
+ GST_ERROR_OBJECT (maruenc, "Failed to encode buffer: %d", res);
+ gst_buffer_unref (outbuf);
+ return GST_FLOW_OK;
+ }
+ GST_LOG_OBJECT (maruenc, "got output size %d", res);
+
+ GST_BUFFER_SIZE (outbuf) = res;
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+ GST_BUFFER_DURATION (outbuf) = duration;
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ }
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (maruenc->srcpad));
+
+ GST_LOG_OBJECT (maruenc, "pushing size %d, timestamp %",
+ GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp));
+
+ ret = gst_pad_push (maruenc->srcpad, outbuf);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_maruenc_chain_audio (GstPad *pad, GstBuffer *buffer)
+{
+ GstEmulEnc *maruenc;
+ GstEmulEncClass *oclass;
+ GstClockTime timestamp, duration;
+ guint in_size, frame_size;
+ gint osize;
+ GstFlowReturn ret;
+ gint out_size = 0;
+ gboolean discont;
+ guint8 *in_data;
+ CodecContext *ctx;
+
+ maruenc = (GstEmulEnc *) (GST_OBJECT_PARENT (pad));
+ oclass = (GstEmulEncClass *) G_OBJECT_GET_CLASS (maruenc);
+
+ ctx = maruenc->context;
+
+ in_size = GST_BUFFER_SIZE (buffer);
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+ discont = GST_BUFFER_IS_DISCONT (buffer);
+
+ GST_DEBUG_OBJECT (maruenc,
+ "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
+ ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), in_size);
+
+ frame_size = ctx->audio.frame_size;
+ osize = ctx->audio.bits_per_sample_fmt;
+
+ if (frame_size > 1) {
+ guint avail, frame_bytes;
+
+ if (discont) {
+ GST_LOG_OBJECT (maruenc, "DISCONT, clear adapter");
+ gst_adapter_clear (maruenc->adapter);
+ maruenc->discont = TRUE;
+ }
+
+ if (gst_adapter_available (maruenc->adapter) == 0) {
+ GST_LOG_OBJECT (maruenc, "taking buffer timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+ maruenc->adapter_ts = timestamp;
+ maruenc->adapter_consumed = 0;
+ } else {
+ GstClockTime upstream_time;
+ GstClockTime consumed_time;
+ guint64 bytes;
+
+ consumed_time =
+ gst_util_uint64_scale (maruenc->adapter_consumed, GST_SECOND,
+ ctx->audio.sample_rate);
+ timestamp = maruenc->adapter_ts + consumed_time;
+ GST_LOG_OBJECT (maruenc, "taking adapter timestamp %" GST_TIME_FORMAT
+ " and adding consumed time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (maruenc->adapter_ts), GST_TIME_ARGS (consumed_time));
+
+ upstream_time = gst_adapter_prev_timestamp (maruenc->adapter, &bytes);
+ if (GST_CLOCK_TIME_IS_VALID (upstream_time)) {
+ GstClockTimeDiff diff;
+
+ upstream_time +=
+ gst_util_uint64_scale (bytes, GST_SECOND,
+ ctx->audio.sample_rate * osize * ctx->audio.channels);
+ diff = upstream_time - timestamp;
+
+ if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) {
+ GST_DEBUG_OBJECT (maruenc, "adapter timestamp drifting, "
+ "taking upstream timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (upstream_time));
+ timestamp = upstream_time;
+
+ maruenc->adapter_consumed = bytes / (osize * ctx->audio.channels);
+ maruenc->adapter_ts =
+ upstream_time - gst_util_uint64_scale (maruenc->adapter_consumed,
+ GST_SECOND, ctx->audio.sample_rate);
+ maruenc->discont = TRUE;
+ }
+ }
+ }
+
+ GST_LOG_OBJECT (maruenc, "pushing buffer in adapter");
+ gst_adapter_push (maruenc->adapter, buffer);
+
+ frame_bytes = frame_size * osize * ctx->audio.channels;
+ avail = gst_adapter_available (maruenc->adapter);
+
+ GST_LOG_OBJECT (maruenc, "frame_bytes %u, avail %u", frame_bytes, avail);
+
+ while (avail >= frame_bytes) {
+ GST_LOG_OBJECT (maruenc, "taking %u bytes from the adapter", frame_bytes);
+
+ in_data = (guint8 *) gst_adapter_peek (maruenc->adapter, frame_bytes);
+ maruenc->adapter_consumed += frame_size;
+
+ duration =
+ gst_util_uint64_scale (maruenc->adapter_consumed, GST_SECOND,
+ ctx->audio.sample_rate);
+ duration -= (timestamp - maruenc->adapter_ts);
+
+ out_size = frame_bytes * 4;
+
+ ret =
+ gst_maruenc_encode_audio (maruenc, in_data, frame_bytes, out_size,
+ timestamp, duration, maruenc->discont);
+
+ gst_adapter_flush (maruenc->adapter, frame_bytes);
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (maruenc, "Failed to push buffer %d (%s)", ret,
+ gst_flow_get_name (ret));
+ }
+
+ timestamp += duration;
+
+ maruenc->discont = FALSE;
+ avail = gst_adapter_available (maruenc->adapter);
+ }
+ GST_LOG_OBJECT (maruenc, "%u bytes left in the adapter", avail);
+ } else {
+#if 0
+ int coded_bps = av_get_bits_per_sample (oclass->codec->name);
+
+ GST_LOG_OBJECT (maruenc, "coded bps %d, osize %d", coded_bps, osize);
+
+ out_size = in_size / osize;
+ if (coded_bps) {
+ out_size = (out_size * coded_bps) / 8;
+ }
+#endif
+ in_data = (guint8 *) GST_BUFFER_DATA (buffer);
+ ret = gst_maruenc_encode_audio (maruenc, in_data, in_size, out_size,
+ timestamp, duration, discont);
+ gst_buffer_unref (buffer);
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (maruenc, "Failed to push buffer %d (%s)", ret,
+ gst_flow_get_name (ret));
+ }
+ }
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_maruenc_flush_buffers (GstEmulEnc *maruenc, gboolean send)
+{
+ GstBuffer *outbuf, *inbuf;
+ gint ret_size = 0;
+
+ GST_DEBUG_OBJECT (maruenc, "flushing buffers with sending %d", send);
+
+ if (!maruenc->opened) {
+ while (!g_queue_is_empty (maruenc->delay)) {
+ gst_buffer_unref (g_queue_pop_head (maruenc->delay));
+ }
+ }
+
+#if 0
+ while (!g_queue_is_empty (maruenc->delay)) {
+ maruenc_setup_working_buf (maruenc);
+
+ ret_size = codec_encode_video (maruenc->context,
+ maruenc->working_buf, maruenc->working_buf_size, NULL, NULL, 0,
+ maruenc->dev);
+
+ if (ret_size < 0) {
+ GstEmulEncClass *oclass =
+ (GstEmulEncClass *) (G_OBJECT_GET_CLASS (maruenc));
+ GST_WARNING_OBJECT (maruenc,
+ "maru_%senc: failed to flush buffer", oclass->codec->name);
+ break;
+ }
+
+ if (maruenc->file && maruenc->context->stats_out) {
+ if (fprintf (maruenc->file, "%s", maruenc->context->stats_out) < 0) {
+ GST_ELEMENT_ERROR (emeulenc, RESOURCE, WRITE,
+ (("Could not write to file \"%s\"."), maruenc->filename),
+ GST_ERROR_SYSTEM);
+ }
+ }
+
+ inbuf = g_queue_pop_head (maruenc->delay);
+
+ outbuf = gst_buffer_new_and_alloc (ret_size);
+ memcpy (GST_BUFFER_DATA (outbuf), maruenc->working_buf, ret_size);
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
+ GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
+
+ if (!maruenc->context->coded_frame->key_frame) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (maruenc->srcpad));
+
+ gst_buffer_unref (inbuf);
+
+ if (send) {
+ gst_pad_push (maruenc->srcpad, outbuf);
+ } else {
+ gst_buffer_unref (outbuf);
+ }
+ }
+
+ while (!g_queue_is_empty (maruenc->delay)) {
+ gst_buffer_unref (g_queue_pop_head (maruenc->delay));
+ }
+#endif
+}
+
+static gboolean
+gst_maruenc_event_video (GstPad *pad, GstEvent *event)
+{
+ GstEmulEnc *maruenc;
+ maruenc = (GstEmulEnc *) gst_pad_get_parent (pad);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ gst_maruenc_flush_buffers (maruenc, TRUE);
+ break;
+ case GST_EVENT_CUSTOM_DOWNSTREAM:
+ {
+ const GstStructure *s;
+ s = gst_event_get_structure (event);
+
+ if (gst_structure_has_name (s, "GstForceKeyUnit")) {
+#if 0
+ maruenc->picture->pict_type = FF_I_TYPE;
+#endif
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return gst_pad_push_event (maruenc->srcpad, event);
+}
+
+static gboolean
+gst_maruenc_event_src (GstPad *pad, GstEvent *event)
+{
+ GstEmulEnc *maruenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
+ gboolean forward = TRUE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CUSTOM_UPSTREAM:
+ {
+ const GstStructure *s;
+ s = gst_event_get_structure (event);
+
+ if (gst_structure_has_name (s, "GstForceKeyUnit")) {
+#if 0
+ GST_OBJECT_LOCK (maruenc);
+ maruenc->force_keyframe = TRUE;
+ GST_OBJECT_UNLOCK (maruenc);
+#endif
+ forward = FALSE;
+ gst_event_unref (event);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (forward) {
+ return gst_pad_push_event (maruenc->sinkpad, event);
+ }
+
+ return TRUE;
+}
+
+GstStateChangeReturn
+gst_maruenc_change_state (GstElement *element, GstStateChange transition)
+{
+ GstEmulEnc *maruenc = (GstEmulEnc*)element;
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_maruenc_flush_buffers (maruenc, FALSE);
+ if (maruenc->opened) {
+ gst_maru_avcodec_close (maruenc->context, maruenc->dev);
+ maruenc->opened = FALSE;
+ }
+ gst_adapter_clear (maruenc->adapter);
+
+#if 0
+ if (maruenc->flie) {
+ fclose (maruenc->file);
+ maruenc->file = NULL;
+ }
+#endif
+
+ if (maruenc->working_buf) {
+ g_free (maruenc->working_buf);
+ maruenc->working_buf = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_maruenc_register (GstPlugin *plugin, GList *element)
+{
+ GTypeInfo typeinfo = {
+ sizeof (GstEmulEncClass),
+ (GBaseInitFunc) gst_maruenc_base_init,
+ NULL,
+ (GClassInitFunc) gst_maruenc_class_init,
+ NULL,
+ NULL,
+ sizeof (GstEmulEnc),
+ 0,
+ (GInstanceInitFunc) gst_maruenc_init,
+ };
+
+ GType type;
+ gchar *type_name;
+ gint rank = GST_RANK_NONE;
+ GList *elem = element;
+ CodecElement *codec = NULL;
+
+ if (!elem) {
+ return FALSE;
+ }
+
+ /* register element */
+ do {
+ codec = (CodecElement *)(elem->data);
+ if (!codec) {
+ return FALSE;
+ }
+
+ if (codec->codec_type != CODEC_TYPE_ENCODE) {
+ continue;
+ }
+
+ type_name = g_strdup_printf ("maru_%senc", 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_MARUENC_PARAMS_QDATA, (gpointer) codec);
+ }
+
+ if (!gst_element_register (plugin, type_name, rank, type)) {
+ g_free (type_name);
+ return FALSE;
+ }
+ g_free (type_name);
+ } while ((elem = elem->next));
+
+ return TRUE;
+}
--- /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 "gstmaru.h"
+#include "gstmaruinterface.h"
+#include "gstmarumem.h"
+#include "gstmarudevice.h"
+
+extern int device_fd;
+extern gpointer device_mem;
+
+struct mem_info {
+ gpointer start;
+ uint32_t offset;
+};
+
+typedef struct _CodecHeader {
+ int32_t api_index;
+ uint32_t mem_offset;
+} CodecHeader;
+
+#define SMALL_BUFFER (256 * 1024)
+#define MEDIUM_BUFFER (2 * 1024 * 1024)
+#define LARGE_BUFFER (4 * 1024 * 1024)
+
+#define CODEC_META_DATA_SIZE 256
+
+static int
+_codec_header (int32_t api_index, uint32_t mem_offset, uint8_t *device_buf)
+{
+ CodecHeader header = { 0 };
+
+ CODEC_LOG (DEBUG, "enter, %s\n", __func__);
+
+ header.api_index = api_index;
+ header.mem_offset = mem_offset;
+
+ memcpy(device_buf, &header, sizeof(header));
+
+ CODEC_LOG (DEBUG, "leave, %s\n", __func__);
+
+ return sizeof(header);
+}
+
+static void
+_codec_write_to_qemu (int32_t ctx_index, int32_t api_index,
+ uint32_t mem_offset, int fd)
+{
+ CodecIOParams ioparam;
+
+ memset(&ioparam, 0, sizeof(ioparam));
+ ioparam.api_index = api_index;
+ ioparam.ctx_index = ctx_index;
+ ioparam.mem_offset = mem_offset;
+ if (write (fd, &ioparam, 1) < 0) {
+ fprintf (stderr, "%s, failed to write copy data.\n", __func__);
+ }
+}
+
+static struct mem_info
+secure_device_mem (guint buf_size)
+{
+ int ret = 0;
+ uint32_t mem_offset = 0, cmd;
+ struct mem_info info;
+
+ CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+ if (buf_size < SMALL_BUFFER) {
+ cmd = CODEC_CMD_SECURE_SMALL_BUFFER;
+ CODEC_LOG (DEBUG, "small buffer size\n");
+ } else if (buf_size < MEDIUM_BUFFER) {
+ // HD Video(2MB)
+ cmd = CODEC_CMD_SECURE_MEDIUM_BUFFER;
+ CODEC_LOG (DEBUG, "HD buffer size\n");
+ } else {
+ // FULL HD Video(4MB)
+ cmd = CODEC_CMD_SECURE_LARGE_BUFFER;
+ CODEC_LOG (DEBUG, "FULL HD buffer size\n");
+ }
+
+ ret = ioctl (device_fd, cmd, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed to get available buffer\n");
+ // FIXME:
+ } else {
+ if (mem_offset == (LARGE_BUFFER * 8)) {
+ CODEC_LOG (ERR, "acquired memory is over!!\n");
+ } else {
+ info.start = (gpointer)((uint32_t)device_mem + mem_offset);
+ info.offset = mem_offset;
+
+ CODEC_LOG (DEBUG, "acquire device_memory: 0x%x\n", mem_offset);
+ }
+ }
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return info;
+}
+
+static void
+release_device_mem (gpointer start)
+{
+ int ret;
+ uint32_t offset = start - device_mem;
+
+ CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+ CODEC_LOG (DEBUG, "release device_mem start: %p, offset: 0x%x\n", start, offset);
+ ret = ioctl (device_fd, CODEC_CMD_RELEASE_BUFFER, &offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed to release buffer\n");
+ }
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+}
+
+static void
+codec_buffer_free (gpointer start)
+{
+ CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+ release_device_mem (start);
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+}
+
+GstFlowReturn
+codec_buffer_alloc (GstPad *pad, guint64 offset, guint size,
+ GstCaps *caps, GstBuffer **buf)
+{
+ struct mem_info info;
+
+ CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+ *buf = gst_buffer_new ();
+
+ info = secure_device_mem (size);
+
+ CODEC_LOG (DEBUG, "memory start: 0x%p, offset 0x%x\n",
+ info.start, info.offset);
+
+ GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = info.start;
+ GST_BUFFER_SIZE (*buf) = size;
+ GST_BUFFER_FREE_FUNC (*buf) = codec_buffer_free;
+ GST_BUFFER_OFFSET (*buf) = offset;
+
+ if (caps) {
+ gst_buffer_set_caps (*buf, caps);
+ }
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return GST_FLOW_OK;
+}
+
+int
+codec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
+{
+ int fd, ret = 0;
+ int opened, size = 0;
+ uint8_t *mmapbuf = NULL;
+ uint32_t meta_offset = 0;
+
+ CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+ fd = dev->fd;
+ if (fd < 0) {
+ GST_ERROR ("failed to get %s fd.\n", CODEC_DEV);
+ return -1;
+ }
+
+ mmapbuf = (uint8_t *)dev->buf;
+ if (!mmapbuf) {
+ GST_ERROR ("failed to get mmaped memory address.\n");
+ return -1;
+ }
+
+ ret = ioctl(fd, CODEC_CMD_GET_CONTEXT_INDEX, &ctx->index);
+ if (ret < 0) {
+ GST_ERROR ("failed to get context index\n");
+ return -1;
+ }
+ CODEC_LOG (DEBUG, "get context index: %d\n", ctx->index);
+
+ meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
+ CODEC_LOG (DEBUG,
+ "init. ctx: %d meta_offset = 0x%x\n", ctx->index, meta_offset);
+
+// size = _codec_header (CODEC_INIT, 0, mmapbuf + meta_offset);
+ size = 8;
+ _codec_init_meta_to (ctx, codec, mmapbuf + meta_offset + size);
+
+ _codec_write_to_qemu (ctx->index, CODEC_INIT, 0, fd);
+
+ CODEC_LOG (DEBUG,
+ "init. ctx: %d meta_offset = 0x%x, size: %d\n", ctx->index, meta_offset, size);
+
+#if 0
+ if (codec->media_type == AVMEDIA_TYPE_AUDIO) {
+ CODEC_LOG (DEBUG,
+ "opened: %d, audio_sample_fmt: %d\n",
+ *(int *)(mmapbuf + meta_offset + size),
+ *(int *)(mmapbuf + meta_offset + size + 4));
+ }
+#endif
+
+ opened =
+ _codec_init_meta_from (ctx, codec->media_type, mmapbuf + meta_offset + size);
+ ctx->codec= codec;
+
+ CODEC_LOG (DEBUG, "opened: %d\n", opened);
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return opened;
+}
+
+void
+codec_deinit (CodecContext *ctx, CodecDevice *dev)
+{
+ int fd;
+ void *mmapbuf = NULL;
+
+ CODEC_LOG (DEBUG, "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_LOG (INFO, "close. context index: %d\n", ctx->index);
+ _codec_write_to_qemu (ctx->index, CODEC_DEINIT, 0, fd);
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+}
+
+int
+codec_decode_video (CodecContext *ctx, uint8_t *in_buf, int in_size,
+ gint idx, gint64 in_offset, GstBuffer **out_buf,
+ int *got_picture_ptr, CodecDevice *dev)
+{
+ int fd, len = 0;
+ int ret, size = 0;
+ uint8_t *mmapbuf = NULL;
+ uint32_t mem_offset = 0, meta_offset = 0;
+
+ CODEC_LOG (DEBUG, "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;
+ }
+
+ ret = ioctl (fd, CODEC_CMD_SECURE_SMALL_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR,
+ "decode_audio. failed to get available memory to write inbuf\n");
+ return -1;
+ }
+ CODEC_LOG (DEBUG, "decode_video. mem_offset = 0x%x\n", mem_offset);
+
+ meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
+ CODEC_LOG (DEBUG, "decode_video. meta_offset = 0x%x\n", meta_offset);
+
+// size = _codec_header (CODEC_DECODE_VIDEO, mem_offset, mmapbuf + meta_offset);
+ size = 8;
+ _codec_decode_video_meta_to (in_size, idx, in_offset, mmapbuf + meta_offset + size);
+ _codec_decode_video_inbuf (in_buf, in_size, mmapbuf + mem_offset);
+
+ dev->mem_info.offset = mem_offset;
+ _codec_write_to_qemu (ctx->index, CODEC_DECODE_VIDEO, mem_offset, fd);
+
+ // after decoding video, no need to get outbuf.
+ len =
+ _codec_decode_video_meta_from (&ctx->video, got_picture_ptr, mmapbuf + meta_offset + size);
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return len;
+}
+
+void
+codec_picture_copy (CodecContext *ctx, uint8_t *pict,
+ uint32_t pict_size, CodecDevice *dev)
+{
+ int fd, ret = 0;
+ void *mmapbuf = NULL;
+
+ CODEC_LOG (DEBUG, "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_LOG (DEBUG, "pict_size: %d\n", pict_size);
+
+// if (pict_size < MEDIUM_BUFFER) {
+ if (pict_size < (SMALL_BUFFER)) {
+ dev->mem_info.offset = (uint32_t)pict - (uint32_t)mmapbuf;
+ CODEC_LOG (DEBUG, "pict: %p , device_mem: %p\n", pict, mmapbuf);
+ CODEC_LOG (DEBUG, "picture_copy, mem_offset = 0x%x\n", dev->mem_info.offset);
+ }
+
+ _codec_write_to_qemu (ctx->index, CODEC_PICTURE_COPY,
+ dev->mem_info.offset, fd);
+// if (pict_size < MEDIUM_BUFFER) {
+ if (pict_size < SMALL_BUFFER) {
+ CODEC_LOG (DEBUG,
+ "set the mem_offset as outbuf: 0x%x\n", dev->mem_info.offset);
+ ret = ioctl (fd, CODEC_CMD_USE_DEVICE_MEM, &(dev->mem_info.offset));
+ if (ret < 0) {
+ // FIXME:
+ }
+ } else if (pict_size < MEDIUM_BUFFER) {
+ uint32_t mem_offset = 0;
+ CODEC_LOG (DEBUG, "require to use medium size of memory\n");
+
+ ret = ioctl (fd, CODEC_CMD_GET_DATA_FROM_MEDIUM_BUFFER, &mem_offset);
+ if (ret < 0) {
+ return;
+ }
+ CODEC_LOG (DEBUG, "picture_copy, mem_offset = 0x%x\n", mem_offset);
+
+ memcpy (pict, mmapbuf + mem_offset, pict_size);
+
+ ret = ioctl(fd, CODEC_CMD_RELEASE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed release used memory\n");
+ }
+ } else {
+ uint32_t mem_offset = 0;
+ CODEC_LOG (DEBUG, "require to use large size of memory\n");
+
+ ret = ioctl (fd, CODEC_CMD_GET_DATA_FROM_LARGE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ return;
+ }
+ CODEC_LOG (DEBUG, "picture_copy, mem_offset = 0x%x\n", mem_offset);
+
+ memcpy (pict, mmapbuf + mem_offset, pict_size);
+
+ ret = ioctl(fd, CODEC_CMD_RELEASE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed release used memory\n");
+ }
+ }
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+}
+
+int
+codec_decode_audio (CodecContext *ctx, int16_t *samples,
+ int *have_data, uint8_t *in_buf,
+ int in_size, CodecDevice *dev)
+{
+ int fd, len = 0;
+ int ret, size = 0;
+ uint8_t *mmapbuf = NULL;
+ uint32_t mem_offset = 0, meta_offset = 0;
+
+ CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+ fd = dev->fd;
+ if (fd < 0) {
+ GST_ERROR("failed to get %s fd\n", CODEC_DEV);
+ return -1;
+ }
+
+ mmapbuf = (uint8_t *)dev->buf;
+ if (!mmapbuf) {
+ GST_ERROR("failed to get mmaped memory address\n");
+ return -1;
+ }
+
+ ret = ioctl (fd, CODEC_CMD_SECURE_SMALL_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR,
+ "decode_audio. failed to get available memory to write inbuf\n");
+ return -1;
+ }
+ CODEC_LOG (DEBUG, "decode audio. mem_offset = 0x%x\n", mem_offset);
+
+ meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
+ CODEC_LOG (DEBUG, "decode_audio. meta_offset = 0x%x\n", meta_offset);
+
+// size = _codec_header (CODEC_DECODE_AUDIO, mem_offset, mmapbuf + meta_offset);
+ size = 8;
+ _codec_decode_audio_meta_to (in_size, mmapbuf + meta_offset + size);
+ _codec_decode_audio_inbuf (in_buf, in_size, mmapbuf + mem_offset);
+
+ dev->mem_info.offset = mem_offset;
+ _codec_write_to_qemu (ctx->index, CODEC_DECODE_AUDIO, mem_offset, fd);
+
+ ret = ioctl (fd, CODEC_CMD_GET_DATA_FROM_SMALL_BUFFER, &mem_offset);
+ if (ret < 0) {
+ return -1;
+ }
+
+ len =
+ _codec_decode_audio_meta_from (&ctx->audio, have_data, mmapbuf + meta_offset + size);
+ if (len > 0) {
+ _codec_decode_audio_outbuf (*have_data, samples, mmapbuf + mem_offset);
+ }
+ memset(mmapbuf + mem_offset, 0x00, sizeof(len));
+
+ ret = ioctl(fd, CODEC_CMD_RELEASE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed release used memory\n");
+ }
+
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return len;
+}
+
+int
+codec_encode_video (CodecContext *ctx, uint8_t *out_buf,
+ int out_size, uint8_t *in_buf,
+ int in_size, int64_t in_timestamp, CodecDevice *dev)
+{
+ int fd, len = 0;
+ int ret, size;
+ uint8_t *mmapbuf = NULL;
+ uint32_t mem_offset = 0, meta_offset = 0;
+
+ CODEC_LOG (DEBUG, "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;
+ }
+
+ if (in_size < SMALL_BUFFER) {
+ CODEC_LOG (DEBUG, "use small size of buffer\n");
+
+ ret = ioctl (fd, CODEC_CMD_SECURE_SMALL_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed to small size of buffer.\n");
+ return -1;
+ }
+ } else if (in_size < MEDIUM_BUFFER) {
+ CODEC_LOG (DEBUG, "use medium size of buffer\n");
+
+ ret = ioctl (fd, CODEC_CMD_SECURE_MEDIUM_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed to small size of buffer.\n");
+ return -1;
+ }
+ } else {
+ CODEC_LOG (DEBUG, "use large size of buffer\n");
+ ret = ioctl (fd, CODEC_CMD_SECURE_LARGE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed to large size of buffer.\n");
+ return -1;
+ }
+ }
+ CODEC_LOG (DEBUG, "encode_video. mem_offset = 0x%x\n", mem_offset);
+
+ meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
+ CODEC_LOG (DEBUG, "encode_video. meta_offset = 0x%x\n", meta_offset);
+
+// size =
+// _codec_header (CODEC_ENCODE_VIDEO, mem_offset, mmapbuf + meta_offset);
+ size = 8;
+ meta_offset += size;
+ _codec_encode_video_meta_to (in_size, in_timestamp, mmapbuf + meta_offset);
+ _codec_encode_video_inbuf (in_buf, in_size, mmapbuf + mem_offset);
+
+ dev->mem_info.offset = mem_offset;
+ _codec_write_to_qemu (ctx->index, CODEC_ENCODE_VIDEO, mem_offset, fd);
+
+#ifndef DIRECT_BUFFER
+ ret = ioctl (fd, CODEC_CMD_GET_DATA_FROM_SMALL_BUFFER, &mem_offset);
+ if (ret < 0) {
+ return -1;
+ }
+ CODEC_LOG (DEBUG, "read, encode_video. mem_offset = 0x%x\n", mem_offset);
+
+ memcpy (&len, mmapbuf + meta_offset, sizeof(len));
+ CODEC_LOG (DEBUG, "encode_video. outbuf size: %d\n", len);
+ if (len > 0) {
+ memcpy (out_buf, mmapbuf + mem_offset, len);
+ out_buf = mmapbuf + mem_offset;
+ }
+
+ dev->mem_info.offset = mem_offset;
+#if 0
+ len =
+ _codec_encode_video_outbuf (out_buf, mmapbuf + mem_offset);
+// memset(mmapbuf + mem_offset, 0x00, sizeof(len));
+#endif
+
+#if 1
+ ret = ioctl(fd, CODEC_CMD_RELEASE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ CODEC_LOG (ERR, "failed release used memory\n");
+ }
+#endif
+#else
+ dev->mem_info.offset = (uint32_t)pict - (uint32_t)mmapbuf;
+ CODEC_LOG (DEBUG, "outbuf: %p , device_mem: %p\n", pict, mmapbuf);
+ CODEC_LOG (DEBUG, "encoded video. mem_offset = 0x%x\n", dev->mem_info.offset);
+
+ ret = ioctl (fd, CODEC_CMD_USE_DEVICE_MEM, &(dev->mem_info.offset));
+ if (ret < 0) {
+ // FIXME:
+ }
+#endif
+ CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+ return len;
+}
+
+int
+codec_encode_audio (CodecContext *ctx, uint8_t *out_buf,
+ int max_size, uint8_t *in_buf,
+ int in_size, CodecDevice *dev)
+{
+ int fd, len = 0;
+ int ret, size;
+ void *mmapbuf = NULL;
+ uint32_t mem_offset = 0, meta_offset = 0;
+
+ CODEC_LOG (DEBUG, "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;
+ }
+
+ ret = ioctl (fd, CODEC_CMD_SECURE_SMALL_BUFFER, &mem_offset);
+ if (ret < 0) {
+ return -1;
+ }
+
+ CODEC_LOG (DEBUG, "write, encode_audio. mem_offset = 0x%x\n", mem_offset);
+
+ meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
+ CODEC_LOG (DEBUG, "encode_audio. meta mem_offset = 0x%x\n", meta_offset);
+
+ size = _codec_header (CODEC_ENCODE_AUDIO, mem_offset,
+ mmapbuf + meta_offset);
+ _codec_encode_audio_meta_to (max_size, in_size, mmapbuf + meta_offset + size);
+ _codec_encode_audio_inbuf (in_buf, in_size, mmapbuf + mem_offset);
+
+ dev->mem_info.offset = mem_offset;
+ _codec_write_to_qemu (ctx->index, CODEC_ENCODE_AUDIO, mem_offset, fd);
+
+ ret = ioctl (fd, CODEC_CMD_GET_DATA_FROM_SMALL_BUFFER, &mem_offset);
+ if (ret < 0) {
+ return -1;
+ }
+
+ CODEC_LOG (DEBUG, "read, encode_video. mem_offset = 0x%x\n", mem_offset);
+
+ len = _codec_encode_audio_outbuf (out_buf, mmapbuf + mem_offset);
+ memset(mmapbuf + mem_offset, 0x00, sizeof(len));
+
+ ret = ioctl(fd, CODEC_CMD_RELEASE_BUFFER, &mem_offset);
+ if (ret < 0) {
+ return -1;
+ }
+
+ CODEC_LOG (DEBUG, "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_MARU_INTERFACE_H__
+#define __GST_MARU_INTERFACE_H__
+
+#include "gstmaru.h"
+
+int
+codec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev);
+
+void
+codec_deinit (CodecContext *ctx, CodecDevice *dev);
+
+int
+codec_decode_video (CodecContext *ctx, uint8_t *in_buf, int in_size,
+ gint idx, gint64 in_offset, GstBuffer **out_buf,
+ int *got_picture_ptr, CodecDevice *dev);
+
+
+int
+codec_decode_audio (CodecContext *ctx, int16_t *samples,
+ int *frame_size_ptr, uint8_t *in_buf,
+ int in_size, CodecDevice *dev);
+
+int
+codec_encode_video (CodecContext *ctx, uint8_t*out_buf,
+ int out_size, uint8_t *in_buf,
+ int in_size, int64_t in_timestamp,
+ CodecDevice *dev);
+
+int
+codec_encode_audio (CodecContext *ctx, uint8_t *out_buf,
+ int out_size, uint8_t *in_buf,
+ int in_size, CodecDevice *dev);
+
+void
+codec_picture_copy (CodecContext *ctx, uint8_t *pict,
+ uint32_t pict_size, CodecDevice *dev);
+
+GstFlowReturn
+codec_buffer_alloc (GstPad *pad, guint64 offset,
+ guint size, GstCaps *caps, GstBuffer **buf);
+
+#endif /* __GST_EMUL_API_H__ */
--- /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 "gstmarumem.h"
+
+/*
+ * codec data such as codec name, longname, media type and etc.
+ */
+static int
+_codec_info_data (CodecElement *codec, uint8_t *device_buf)
+{
+ int size = 0;
+
+ CODEC_LOG (DEBUG, "enter, %s\n", __func__);
+
+ CODEC_LOG (DEBUG, "type: %d, name: %s\n", codec->codec_type, codec->name);
+ memcpy (device_buf, &codec->codec_type, sizeof(codec->codec_type));
+ size = sizeof(codec->codec_type);
+
+ memcpy (device_buf + size, codec->name, sizeof(codec->name));
+ size += sizeof(codec->name);
+
+ CODEC_LOG (DEBUG, "leave, %s\n", __func__);
+
+ return size;
+}
+
+void
+_codec_init_meta_to (CodecContext *ctx,
+ CodecElement *codec,
+ uint8_t *device_buf)
+{
+ int size = 0;
+
+ CODEC_LOG (DEBUG, "enter, %s\n", __func__);
+
+ size = _codec_info_data (codec, device_buf);
+
+ if (codec) {
+ CODEC_LOG (INFO, "name: %s, media type: %s\n",
+ codec->name, codec->media_type ? "AUDIO" : "VIDEO");
+ }
+
+ if (codec->media_type == AVMEDIA_TYPE_AUDIO) {
+ CODEC_LOG (DEBUG,
+ "before init. audio sample_fmt: %d\n", ctx->audio.sample_fmt);
+ CODEC_LOG (DEBUG,
+ "before init. audio block_align: %d\n", ctx->audio.block_align);
+ }
+
+ CODEC_LOG (DEBUG, "init. write data to qemu, size: %d\n", size);
+ memcpy (device_buf + size, ctx, sizeof(CodecContext) - 12);
+ size += (sizeof(CodecContext) - 12);
+ memcpy (device_buf + size, ctx->codecdata, ctx->codecdata_size);
+
+ CODEC_LOG (DEBUG, "leave, %s\n", __func__);
+}
+
+int
+_codec_init_meta_from (CodecContext *ctx,
+ int media_type,
+ uint8_t *device_buf)
+{
+ int ret = 0, size = 0;
+
+ CODEC_LOG (DEBUG, "after init. read data from device.\n");
+
+ memcpy (&ret, device_buf, sizeof(ret));
+ size = sizeof(ret);
+ if (!ret) {
+ if (media_type == AVMEDIA_TYPE_AUDIO) {
+ AudioData audio = { 0 };
+
+#if 0
+ memcpy(&audio, device_buf + size, sizeof(AudioData));
+ ctx->audio.sample_fmt = audio.sample_fmt;
+ ctx->audio.frame_size = audio.frame_size;
+ ctx->audio.bits_per_sample_fmt = audio.bits_per_sample_fmt;
+#endif
+ CODEC_LOG (INFO,
+ "audio sample_fmt: %d\n", *(int *)(device_buf + size));
+
+ memcpy(&ctx->audio.sample_fmt, device_buf + size, sizeof(audio.sample_fmt));
+ size += sizeof(audio.sample_fmt);
+ memcpy(&ctx->audio.frame_size, device_buf + size, sizeof(audio.frame_size));
+ size += sizeof(audio.frame_size);
+ memcpy(&ctx->audio.bits_per_sample_fmt, device_buf + size, sizeof(audio.bits_per_sample_fmt));
+
+ CODEC_LOG (INFO,
+ "after init. audio sample_fmt: %d\n", ctx->audio.sample_fmt);
+ }
+ } else {
+ CODEC_LOG (ERR, "failed to open codec context\n");
+ }
+
+ return ret;
+}
+
+void
+_codec_decode_video_meta_to (int in_size, int idx, int64_t in_offset, uint8_t *device_buf)
+{
+ memcpy (device_buf, &in_size, sizeof(in_size));
+ memcpy (device_buf + sizeof(in_size), &idx, sizeof(idx));
+ memcpy (device_buf + sizeof(idx), &in_offset, sizeof(in_offset));
+}
+
+void
+_codec_decode_video_inbuf (uint8_t *in_buf, int in_size,
+ uint8_t *device_buf)
+{
+ int size = 0;
+
+ memcpy(device_buf, &in_size, sizeof(in_size));
+ size = sizeof(in_size);
+ if (in_size > 0 ) {
+ memcpy (device_buf + size, in_buf, in_size);
+ }
+
+ CODEC_LOG (DEBUG, "decode_video. inbuf_size: %d\n", in_size);
+}
+
+
+int
+_codec_decode_video_meta_from (VideoData *video,
+ int *got_picture_ptr,
+ uint8_t *device_buf)
+{
+ int len = 0, size = 0;
+
+ CODEC_LOG (DEBUG, "decode_video. read data from qemu.\n");
+
+ memcpy (&len, device_buf, sizeof(len));
+ size = sizeof(len);
+ memcpy (got_picture_ptr,
+ device_buf + size, sizeof(*got_picture_ptr));
+ size += sizeof(*got_picture_ptr);
+ memcpy (video, device_buf + size, sizeof(VideoData));
+
+ CODEC_LOG (DEBUG, "decode_video. len: %d, have_data: %d\n",
+ len, *got_picture_ptr);
+
+ return len;
+}
+
+void
+_codec_decode_audio_meta_to (int in_size, uint8_t *device_buf)
+{
+ memcpy (device_buf, &in_size, sizeof(in_size));
+}
+
+
+void
+_codec_decode_audio_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf)
+{
+ int size = 0;
+
+ memcpy (device_buf, &in_size, sizeof(in_size));
+ size = sizeof(in_size);
+ if (in_size > 0) {
+ memcpy (device_buf + size, in_buf, in_size);
+ }
+
+ CODEC_LOG (DEBUG, "decode_audio. inbuf_size: %d\n", in_size);
+}
+
+int
+_codec_decode_audio_meta_from (AudioData *audio, int *frame_size_ptr,
+ uint8_t *device_buf)
+{
+ int len = 0, size = 0;
+
+ CODEC_LOG (DEBUG, "decode_audio. read data from device.\n");
+
+ memcpy (&audio->channel_layout,
+ device_buf, sizeof(audio->channel_layout));
+ size = sizeof(audio->channel_layout);
+ memcpy (&len, device_buf + size, sizeof(len));
+ size += sizeof(len);
+ memcpy (frame_size_ptr, device_buf + size, sizeof(*frame_size_ptr));
+
+ CODEC_LOG (DEBUG, "decode_audio. len: %d, frame_size: %d\n",
+ len, (*frame_size_ptr));
+
+ return len;
+}
+
+void
+_codec_decode_audio_outbuf (int outbuf_size, int16_t *samples, uint8_t *device_buf)
+{
+ CODEC_LOG (DEBUG, "decode_audio. read outbuf %d\n", outbuf_size);
+ memcpy (samples, device_buf, outbuf_size);
+}
+
+void
+_codec_encode_video_meta_to (int in_size, int64_t in_timestamp, uint8_t *device_buf)
+{
+ CODEC_LOG (DEBUG, "encode_video. write data to device.\n");
+
+ memcpy (device_buf, &in_size, sizeof(in_size));
+ memcpy (device_buf + sizeof(in_size), &in_timestamp, sizeof(in_timestamp));
+}
+
+void
+_codec_encode_video_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf)
+{
+ int size = 0;
+
+ memcpy ((uint8_t *)device_buf, &in_size, sizeof(in_size));
+ size += sizeof(in_size);
+ if (in_size > 0) {
+ memcpy (device_buf + size, in_buf, in_size);
+ }
+ CODEC_LOG (DEBUG, "encode_video. inbuf_size: %d\n", in_size);
+}
+
+void
+_codec_encode_video_outbuf (int len, uint8_t *out_buf, uint8_t *device_buf)
+{
+// int len, size;
+
+ CODEC_LOG (DEBUG, "encode_video. read data from device.\n");
+
+// memcpy (&len, device_buf, sizeof(len));
+// size = sizeof(len);
+ memcpy (out_buf, device_buf, len);
+
+// return len;
+}
+
+void
+_codec_encode_audio_meta_to (int max_size, int in_size, uint8_t *device_buf)
+{
+ int size = 0;
+
+ CODEC_LOG (DEBUG, "encode_audio. write data to device.\n");
+
+ memcpy (device_buf, &in_size, sizeof(in_size));
+ size = sizeof(in_size);
+ memcpy (device_buf + size, &max_size, sizeof(max_size));
+}
+
+void
+_codec_encode_audio_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf)
+{
+ int size = 0;
+
+ memcpy (device_buf, &in_size, sizeof(in_size));
+ size = sizeof(in_size);
+ if (in_size > 0) {
+ memcpy (device_buf + size, in_buf, in_size);
+ }
+ CODEC_LOG (DEBUG, "encode_audio. inbuf_size: %d\n", in_size);
+}
+
+int
+_codec_encode_audio_outbuf (uint8_t *out_buf, uint8_t *device_buf)
+{
+ int len, size;
+
+ CODEC_LOG (DEBUG, "encode_audio. read data from device\n");
+
+ memcpy (&len, (uint8_t *)device_buf, sizeof(len));
+ size = sizeof(len);
+ memcpy (out_buf, (uint8_t *)device_buf + size, len);
+
+ 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_MARU_MEM_H__
+#define __GST_MARU_MEM_H__
+
+#include "gstmaru.h"
+
+void _codec_init_meta_to (CodecContext *ctx, CodecElement *codec, uint8_t *device_buf);
+
+int _codec_init_meta_from (CodecContext *ctx, int media_type, uint8_t *device_buf);
+
+void _codec_decode_video_meta_to (int in_size, int idx, int64_t in_offset, uint8_t *device_buf);
+
+void _codec_decode_video_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf);
+
+int _codec_decode_video_meta_from (VideoData *video, int *got_picture_ptr,
+ uint8_t *device_buf);
+
+void _codec_decode_audio_meta_to (int in_size, uint8_t *device_buf);
+
+
+void _codec_decode_audio_inbuf (uint8_t *in_buf, int in_size,
+ uint8_t *device_buf);
+
+int _codec_decode_audio_meta_from (AudioData *audio, int *frame_size_ptr,
+ uint8_t *device_buf);
+
+void _codec_decode_audio_outbuf (int outbuf_size, int16_t *samples,
+ uint8_t *device_buf);
+
+void _codec_encode_video_meta_to (int in_size, int64_t in_timestamp, uint8_t *device_buf);
+
+void _codec_encode_video_inbuf (uint8_t *in_buf, int in_size,
+ uint8_t *device_buf);
+
+void _codec_encode_video_outbuf (int len, uint8_t *outbuf, uint8_t *device_buf);
+
+void _codec_encode_audio_meta_to (int max_size, int in_size, uint8_t *device_buf);
+
+void _codec_encode_audio_inbuf (uint8_t *in_buf, int in_size, uint8_t *device_buf);
+
+int _codec_encode_audio_outbuf (uint8_t *out_buf, uint8_t *device_buf);
+
+#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 "gstmaruutils.h"
+#include <gst/audio/multichannel.h>
+#include <gst/pbutils/codec-utils.h>
+
+gint
+gst_maru_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_maru_codectype_to_video_caps (CodecContext *ctx, const char *name,
+ gboolean encode, CodecElement *codec)
+{
+ GstCaps *caps;
+
+ GST_DEBUG ("context: %p, codec: %s, encode: %d, pixel format: %d",
+ ctx, name, encode, ctx->video.pix_fmt);
+
+ if (ctx) {
+ caps = gst_maru_pixfmt_to_caps (ctx->video.pix_fmt, ctx, name);
+ } else {
+ GstCaps *temp;
+ enum PixelFormat i;
+ CodecContext ctx;
+
+ caps = gst_caps_new_empty ();
+ for (i = 0; i <= PIX_FMT_NB; i++) {
+ temp = gst_maru_pixfmt_to_caps (i, encode ? &ctx : NULL, name);
+ if (temp != NULL) {
+ gst_caps_append (caps, temp);
+ }
+ }
+ }
+
+ return caps;
+}
+
+GstCaps *
+gst_maru_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 (ctx) {
+ caps = gst_maru_smpfmt_to_caps (ctx->audio.sample_fmt, ctx, name);
+#if 1
+ } else if (codec && codec->sample_fmts[0] != -1){
+ GstCaps *temp;
+ int i;
+
+ caps = gst_caps_new_empty ();
+ for (i = 0; codec->sample_fmts[i] != -1; i++) {
+ temp =
+ gst_maru_smpfmt_to_caps (codec->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_maru_smpfmt_to_caps (i, encode ? &ctx : NULL, name);
+ if (temp != NULL) {
+ gst_caps_append (caps, temp);
+ }
+ }
+ }
+
+ return caps;
+}
+
+GstCaps*
+gst_maru_codectype_to_caps (int media_type, CodecContext *ctx,
+ const char *name, gboolean encode)
+{
+ GstCaps *caps;
+
+ switch (media_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ caps =
+ gst_maru_codectype_to_video_caps (ctx, name, encode, NULL);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ caps =
+ gst_maru_codectype_to_audio_caps (ctx, name, encode, NULL);
+ break;
+ default:
+ caps = NULL;
+ break;
+ }
+
+ return caps;
+}
+
+void
+gst_maru_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);
+ ctx->video.ticks_per_frame = 1;
+
+ 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;
+ }
+ }
+// printf ("get pixel format: %d, fourcc: %d\n", ctx->video.pix_fmt, fourcc);
+ } 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_maru_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);
+ gst_structure_get_int (str, "bitrate", &ctx->bit_rate);
+
+ if (!raw) {
+ return;
+ }
+
+ name = gst_structure_get_name (str);
+
+ 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 (gst_structure_get_int (str, "width", &width) &&
+ gst_structure_get_int (str, "depth", &depth) &&
+ gst_structure_get_boolean (str, "signed", &signedness) &&
+ gst_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 = SAMPLE_FMT_S32;
+ }
+ }
+ }
+ }
+}
+
+void
+gst_maru_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);
+ GST_DEBUG ("extradata: %p, size: %d\n", data, 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 (!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');
+ }
+#if 0
+ } else if (strcmp (name, "h263p") == 0) {
+ gboolean val;
+
+ 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_maru_caps_to_pixfmt (caps, ctx, FALSE);
+ // get_palette
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ gst_maru_caps_to_smpfmt (caps, ctx, FALSE);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+gst_maru_caps_to_codecname (const GstCaps *caps, gchar *codec_name, CodecContext *context)
+{
+ const gchar *mimetype;
+ const GstStructure *str;
+ gint wmvversion = 0;
+
+ str = gst_caps_get_structure (caps, 0);
+
+ mimetype = gst_structure_get_name (str);
+
+ if (!strcmp (mimetype, "video/x-wmv")) {
+ gint wmvversion = 0;
+
+ if (gst_structure_get_int (str, "wmvversion", &wmvversion)) {
+ switch (wmvversion) {
+ case 1:
+ g_strlcpy(codec_name, "wmv1", 32);
+ break;
+ case 2:
+ g_strlcpy(codec_name, "wmv2", 32);
+ break;
+ case 3:
+ {
+ guint32 fourcc;
+
+ g_strlcpy(codec_name, "wmv3", 32);
+
+ if (gst_structure_get_fourcc (str, "format", &fourcc)) {
+ if ((fourcc == GST_MAKE_FOURCC ('W', 'V', 'C', '1')) ||
+ (fourcc == GST_MAKE_FOURCC ('W', 'M', 'V', 'A'))) {
+ g_strlcpy(codec_name, "vc1", 32);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+#if 0 // check other types if it needs.
+ } else if () {
+ }
+#endif
+
+#if 0
+ if (context != NULL) {
+ if (video == TRUE) {
+ context->codec_type = CODEC_TYPE_VIDEO;
+ } else if (audio == TRUE) {
+ context->codec_type = CODEC_TYPE_AUDIO;
+ } else {
+ context->codec_type = CODEC_TYPE_UNKNOWN;
+ }
+ context->codec_id = id;
+ gst_maru_caps_with_codecname (name, context->codec_type, caps, context);
+ }
+#endif
+
+ if (codec_name != NULL) {
+ GST_DEBUG ("The %s belongs to the caps %" GST_PTR_FORMAT, codec_name, caps);
+ } else {
+ GST_WARNING ("Couldn't figure out the name for caps %" GST_PTR_FORMAT, caps);
+ }
+}
+
+void
+gst_maru_caps_with_codectype (int media_type, const GstCaps *caps, CodecContext *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ switch (media_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ gst_maru_caps_to_pixfmt (caps, ctx, TRUE);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ gst_maru_caps_to_smpfmt (caps, ctx, TRUE);
+ break;
+ default:
+ break;
+ }
+}
+
+GstCaps *
+gst_maru_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, NULL);
+
+ num = ctx->video.fps_d / ctx->video.ticks_per_frame;
+ denom = ctx->video.fps_n;
+
+ 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 (strcmp (name, "h263") == 0) {
+ /* 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 if (strcmp (name, "none") == 0) {
+ GST_LOG ("default caps");
+ }
+ }
+
+ /* 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_maru_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_maru_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_maru_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_maru_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_maru_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_maru_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_maru_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_maru_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_maru_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_maru_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_maru_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_maru_video_caps_new (ctx, name, "video/x-h263",
+ "variant", G_TYPE_STRING, "itu", NULL);
+ } else {
+ caps = gst_maru_video_caps_new (ctx, "none", "video/x-h263",
+ "variant", G_TYPE_STRING, "itu", NULL);
+ }
+ } else if (strcmp (name, "h263p") == 0) {
+ caps = gst_maru_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
+ switch (ctx->codec_tag) {
+ case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
+ caps = gst_maru_video_caps_new (ctx, name, "video/x-divx",
+ "divxversion", G_TYPE_INT, 5, NULL);
+ break;
+ case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
+ default:
+ caps = gst_maru_video_caps_new (ctx, name, "video/mpeg",
+ "systemstream", G_TYPE_BOOLEAN, FALSE,
+ "mpegversion", G_TYPE_INT, 4, NULL);
+ break;
+ }
+ } else {
+ caps = gst_maru_video_caps_new (ctx, name, "video/mpeg",
+ "mpegversion", G_TYPE_INT, 4,
+ "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (encode) {
+ caps = gst_maru_video_caps_new (ctx, name, "video/mpeg",
+ "mpegversion", G_TYPE_INT, 4,
+ "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ } else {
+ gst_caps_append (caps, gst_maru_video_caps_new (ctx, name,
+ "video/x-divx", "divxversion", GST_TYPE_INT_RANGE, 4, 5, NULL));
+ gst_caps_append (caps, gst_maru_video_caps_new (ctx, name,
+ "video/x-xvid", NULL));
+ gst_caps_append (caps, gst_maru_video_caps_new (ctx, name,
+ "video/x-3ivx", NULL));
+ }
+ }
+ } else if (strcmp (name, "h264") == 0) {
+ caps = gst_maru_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_maru_video_caps_new (ctx, name, "video/x-msmpeg",
+ "msmpegversion", G_TYPE_INT, version, NULL);
+ if (!encode && !strcmp (name, "msmpeg4")) {
+ gst_caps_append (caps, gst_maru_video_caps_new (ctx, name,
+ "video/x-divx", "divxversion", G_TYPE_INT, 3, NULL));
+ }
+ } else if (strcmp (name, "wmv3") == 0) {
+ caps = gst_maru_video_caps_new (ctx, name, "video/x-wmv",
+ "wmvversion", G_TYPE_INT, 3, NULL);
+ } else if (strcmp (name, "vc1") == 0) {
+ caps = gst_maru_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_maru_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 (ctx && ctx->codecdata_size > 0) {
+ gst_codec_utils_aac_caps_set_level_and_profile (caps,
+ ctx->codecdata, ctx->codecdata_size);
+ }
+ }
+ } else if (strcmp (name, "ac3") == 0) {
+ caps = gst_maru_audio_caps_new (ctx, name, "audio/x-ac3", NULL);
+ } else if (strcmp (name, "mp3") == 0) {
+ if (encode) {
+ caps = gst_maru_audio_caps_new (ctx, name, "audio/mpeg",
+ "mpegversion", G_TYPE_INT, 1,
+ "layer", GST_TYPE_INT_RANGE, 1, 3, NULL);
+ } else {
+ 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_maru_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_maru_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];
+
+void
+gst_maru_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_maru_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;
+}
+
+int
+gst_maru_align_size (int buf_size)
+{
+ int i, align_size;
+
+ align_size = buf_size / 1024;
+
+ for (i = 0; i < 14; i++) {
+ if (align_size < (1 << i)) {
+ align_size = 1024 * (1 << i);
+ break;
+ }
+ }
+
+ return align_size;
+}
--- /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_MARU_UTIL_H__
+#define __GST_MARU_UTIL_H__
+
+#include "gstmaru.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_maru_codectype_to_video_caps (CodecContext *ctx, const char *name,
+ gboolean encode, CodecElement *codec);
+
+GstCaps *gst_maru_codectype_to_audio_caps (CodecContext *ctx, const char *name,
+ gboolean encode, CodecElement *codec);
+
+
+GstCaps *gst_maru_codectype_to_caps (int media_type, CodecContext *ctx,
+ const char *name, gboolean encode);
+
+void gst_maru_caps_with_codecname (const char *name, int media_type,
+ const GstCaps *caps, CodecContext *ctx);
+
+void gst_maru_caps_with_codectype (int media_type, const GstCaps *caps, CodecContext *ctx);
+
+GstCaps *gst_maru_video_caps_new (CodecContext *ctx, const char *name,
+ const char *mimetype, const char *fieldname, ...);
+
+GstCaps *gst_maru_audio_caps_new (CodecContext *ctx, const char *name,
+ const char *mimetype, const char *fieldname, ...);
+
+GstCaps *gst_maru_pixfmt_to_caps (enum PixelFormat pix_fmt, CodecContext *ctx, const char *name);
+
+GstCaps *gst_maru_smpfmt_to_caps (int8_t sample_fmt, CodecContext *ctx, const char *name);
+
+GstCaps *gst_maru_codecname_to_caps (const char *name, CodecContext *ctx, gboolean encode);
+
+void gst_maru_init_pix_fmt_info (void);
+
+int gst_maru_avpicture_size (int pix_fmt, int width, int height);
+
+int gst_maru_align_size (int buf_size);
+
+gint gst_maru_smpfmt_depth (int smp_fmt);
+
+#endif