aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2016-08-05 08:30:01 +0000
committerTimo Teräs <timo.teras@iki.fi>2016-08-05 08:30:21 +0000
commit5d66aded2b15e09c1914ec3dd6ceaa5d6e597ae3 (patch)
tree3123dcfaa909844f7479f3778ba01a4b157f5d97 /main
parentd8206ed74a4e40a92216ab8e125ec13faa782232 (diff)
downloadaports-5d66aded2b15e09c1914ec3dd6ceaa5d6e597ae3.tar.bz2
aports-5d66aded2b15e09c1914ec3dd6ceaa5d6e597ae3.tar.xz
main/omxplayer: update snapshot to 2016-08-03
- dbus fix upstreamed - alsa support upstreamed - uses now ffmpeg for rescaling instead of speexdsp
Diffstat (limited to 'main')
-rw-r--r--main/omxplayer/APKBUILD40
-rw-r--r--main/omxplayer/omxplayer-alsa.patch1494
-rw-r--r--main/omxplayer/pull-req-465.patch73
3 files changed, 11 insertions, 1596 deletions
diff --git a/main/omxplayer/APKBUILD b/main/omxplayer/APKBUILD
index 72e96670ef..e0b1ec974d 100644
--- a/main/omxplayer/APKBUILD
+++ b/main/omxplayer/APKBUILD
@@ -1,7 +1,7 @@
# Maintainer: Timo Teräs <timo.teras@iki.fi>
pkgname=omxplayer
-pkgver=0.20160513
-_commitid=8a0fba4128759cc85cf794fc530aa8f91ebad449
+pkgver=0.20160803
+_commitid=350779b00bb7278e0d1d9025b9ed1ddb4a2d99cd
pkgrel=0
pkgdesc="Commandline OMX player for Raspberry Pi"
url="https://github.com/popcornmix/omxplayer"
@@ -9,47 +9,35 @@ arch="armhf"
license="GPLv2"
depends="ttf-freefont"
makedepends="linux-headers raspberrypi-dev ffmpeg-dev pcre-dev
- boost-dev freetype-dev dbus-dev alsa-lib-dev speexdsp-dev"
+ boost-dev freetype-dev dbus-dev alsa-lib-dev"
install=""
subpackages="$pkgname-doc $pkgname-dbg"
source="omxplayer-$pkgver.tar.gz::https://github.com/popcornmix/omxplayer/archive/$_commitid.tar.gz
issue-260.patch
issue-297.patch
- pull-req-465.patch
fix-makefile.patch
default-font.patch
- omxplayer-alsa.patch
omxplayer.initd
omxplayer.confd
"
-_srcdir="$srcdir"/$pkgname-$_commitid
-
-prepare() {
- local i
- cd "$_srcdir"
- for i in $source; do
- case $i in
- *.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;;
- esac
- done
-}
+builddir="$srcdir"/$pkgname-$_commitid
build() {
- cd "$_srcdir"
+ cd "$builddir"
cat <<EOF > Makefile.include
INCLUDES:=-I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
-INCLUDES+=$(pkg-config --cflags freetype2 dbus-1 speexdsp)
+INCLUDES+=$(pkg-config --cflags freetype2 dbus-1)
LDFLAGS:=-L/opt/vc/lib -Wl,-rpath,/opt/vc/lib
-LDFLAGS+=$(pkg-config --libs freetype2 dbus-1 speexdsp)
+LDFLAGS+=$(pkg-config --libs freetype2 dbus-1)
STRIP:=echo
EOF
make omxplayer.bin omxplayer.1
}
package() {
- cd "$_srcdir"
+ cd "$builddir"
make install DIST="$pkgdir" || return 1
rm -rf "$pkgdir"/usr/lib/omxplayer
@@ -59,30 +47,24 @@ package() {
"$pkgdir"/etc/conf.d/$pkgname || return 1
}
-md5sums="30455f3ba035377f21b1e897c496be07 omxplayer-0.20160513.tar.gz
+md5sums="e8351a6a21e51906511aad40f40d8abe omxplayer-0.20160803.tar.gz
a900cdded87b7df503c6599ac43bd8de issue-260.patch
c858882036b9fb03859edf7ce4a1d942 issue-297.patch
-26c3f7593762c604943f09a9b65f331d pull-req-465.patch
7e95d7c8c6bba3a6775473e34df2a2c9 fix-makefile.patch
9ebd96155288809fe0a657cf491e433f default-font.patch
-d84acddc949742c1474ed4f99b88ae47 omxplayer-alsa.patch
b4054a311d76aef91aa10bacd68bc9c4 omxplayer.initd
80e37e7ac04402808015084e26e6072d omxplayer.confd"
-sha256sums="b256bd1f8e74422f23bc9162f89f7b7941ef2ff4a500f9f37d8caf3a779e0526 omxplayer-0.20160513.tar.gz
+sha256sums="1edd3c4b02b69b59435d5c19ab82b90d0da73f8336d9eaba8012d1e9f3b54253 omxplayer-0.20160803.tar.gz
5eb797de354c63a23847a574b103a28d451a4329320f3335f82dc000adbc5c63 issue-260.patch
389c97df4919a3fe4d115f092cb256246e33374150102f0e2cb9ce11456cadb1 issue-297.patch
-8223f7cf72af6c7be282807edd79ed5e7777f7e08339de5fe7d782297a02fba0 pull-req-465.patch
967533d6e13da74a2cf2f78822e55b3cbe7a7736eb8a9a0caed4653c5a98d197 fix-makefile.patch
2bab3d05b12d730737220b8c0052498a34bbebc12b7beb8afb3c054beb0fb3bb default-font.patch
-4ab9a3084321a75bca44b534d92f552b2569a656940eff86d29d76b6ec665722 omxplayer-alsa.patch
e2db0f7ffbe2488dd69ee0bfad006bd863f418554f078ca3432f643de7589d2f omxplayer.initd
530eb9aa50e72fb4828af410b965e0ec7653d1bed87aa86bf04fc340ff3232bd omxplayer.confd"
-sha512sums="e0c34fff244a730f2bafdf8e331ccc386338d618f3017b81a7d28d94897da9f67c48fe97cca0430747f47095af411a3337970e72fd8c9bf9e6bc3ffdbf98ec0b omxplayer-0.20160513.tar.gz
+sha512sums="24521bf5807b21e80698c0dabad8478bdaed31a6ebef9631914da7a6c725ffbf67c4be6c5b944c1933d90dfeed36d2592740a8b25f8bbf5fc172f4650696d440 omxplayer-0.20160803.tar.gz
c349eea5f7c513a07d82a6cf6467c4d21bcb29c053bc5e39d8f675b1212db9beef0abf5248d50ac5a2f14fda73055786f94f421377ffcf5f6bcf8daa2f1b56e8 issue-260.patch
2a8a6def1e09f726cba58c0b9109fa6c4fbd4a3b4f1d27d200488f262a0e0978579d83db7fe24f1d3e03beef318c3674ed79cbd2f1994c4551a59c9fe0f63489 issue-297.patch
-8ac946bf10ad072c7495aa2ad38e66bb718d49c8d73b88e4eeaece24ac7154e0f1e5447f8f101041da4f22db93fd03e770068e6c1c032465d66dbab19ee20183 pull-req-465.patch
48fc451efb9b74da749fe414258b7c4f16e624a86d74a6044025e2134addd994940b7fdda5a4b15cef87a49ebf65dbd1e19d8b73d075a94b485980e4ebd0052a fix-makefile.patch
8aa58aaa07453186302dc68d92f28c1b50bf0f8fccd50359640a7fc8339b233b32a0c8c02284a9974599e56d69cc557acc25e76e6438c6d64d15afd9c1788a8e default-font.patch
-f97ffc5deb8c3ca715dbadd7c1893ea43e2755e891431943fcc836f325493b236181d82c47bd8779c63246a78d471e642c1539bc14240198f388845ade19b95c omxplayer-alsa.patch
3ddd32235d87a46478d0237ee9b253edeb75729e377b09a33069ecdca2ee230d2851f308897ee75ff69a9f3bdd2876f490bc1667a572dce1c186f80fddcf6df3 omxplayer.initd
4f906ada035869a0e515e7615056b18b0f6906ce4b3a2d34081c0efa79bb9455380f729e7c5270180f5ace89c53a7ac7c93f609e6761825f639f44aa22346bb2 omxplayer.confd"
diff --git a/main/omxplayer/omxplayer-alsa.patch b/main/omxplayer/omxplayer-alsa.patch
deleted file mode 100644
index 7b9f3c8c2d..0000000000
--- a/main/omxplayer/omxplayer-alsa.patch
+++ /dev/null
@@ -1,1494 +0,0 @@
-From b03115afd6322093e83b37660727a1a7257cc11d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
-Date: Sat, 14 May 2016 16:27:32 +0300
-Subject: [PATCH] Initial alsa support
-
----
- Makefile | 5 +-
- OMXAudio.cpp | 5 +-
- OMXAudio.h | 1 +
- OMXCore.cpp | 11 +
- README.md | 1 +
- linux/OMXAlsa.cpp | 1314 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- linux/OMXAlsa.h | 11 +
- omxplayer.cpp | 6 +-
- 8 files changed, 1349 insertions(+), 5 deletions(-)
- create mode 100644 linux/OMXAlsa.cpp
- create mode 100644 linux/OMXAlsa.h
-
-diff --git a/Makefile b/Makefile
-index bcfadfb..2857e94 100644
---- a/Makefile
-+++ b/Makefile
-@@ -2,13 +2,14 @@ include Makefile.include
-
- CFLAGS+=-std=c++0x -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -DTARGET_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CMAKE_CONFIG -D__VIDEOCORE4__ -U_FORTIFY_SOURCE -Wall -DHAVE_OMXLIB -DUSE_EXTERNAL_FFMPEG -DHAVE_LIBAVCODEC_AVCODEC_H -DHAVE_LIBAVUTIL_OPT_H -DHAVE_LIBAVUTIL_MEM_H -DHAVE_LIBAVUTIL_AVUTIL_H -DHAVE_LIBAVFORMAT_AVFORMAT_H -DHAVE_LIBAVFILTER_AVFILTER_H -DHAVE_LIBSWRESAMPLE_SWRESAMPLE_H -DOMX -DOMX_SKIP64BIT -ftree-vectorize -DUSE_EXTERNAL_OMX -DTARGET_RASPBERRY_PI -DUSE_EXTERNAL_LIBBCM_HOST
-
--LDFLAGS+=-L./ -Lffmpeg_compiled/usr/local/lib/ -lc -lWFC -lGLESv2 -lEGL -lbcm_host -lopenmaxil -lfreetype -lz
-+LDFLAGS+=-L./ -Lffmpeg_compiled/usr/local/lib/ -lc -lWFC -lGLESv2 -lEGL -lbcm_host -lopenmaxil -lfreetype -lz -lasound
-
- INCLUDES+=-I./ -Ilinux -Iffmpeg_compiled/usr/local/include/ -I /usr/include/dbus-1.0 -I /usr/lib/arm-linux-gnueabihf/dbus-1.0/include
-
- DIST ?= omxplayer-dist
-
--SRC=linux/XMemUtils.cpp \
-+SRC= linux/XMemUtils.cpp \
-+ linux/OMXAlsa.cpp \
- utils/log.cpp \
- DynamicDll.cpp \
- utils/PCMRemap.cpp \
-diff --git a/OMXAudio.cpp b/OMXAudio.cpp
-index e5d6365..99aa093 100644
---- a/OMXAudio.cpp
-+++ b/OMXAudio.cpp
-@@ -104,7 +104,8 @@ bool COMXAudio::PortSettingsChanged()
- }
- if (m_config.device == "omx:both" || m_config.device == "omx:local")
- {
-- if(!m_omx_render_analog.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
-+ const char *component = m_config.alsa_device.empty() ? "OMX.broadcom.audio_render" : "OMX.alsa.audio_render";
-+ if(!m_omx_render_analog.Initialize(component, OMX_IndexParamAudioInit))
- return false;
- }
- if (m_config.device == "omx:both" || m_config.device == "omx:hdmi")
-@@ -235,7 +236,7 @@ bool COMXAudio::PortSettingsChanged()
-
- OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
- OMX_INIT_STRUCTURE(audioDest);
-- strncpy((char *)audioDest.sName, "local", strlen("local"));
-+ strcpy((char *)audioDest.sName, m_config.alsa_device.empty() ? "local" : m_config.alsa_device.c_str());
- omx_err = m_omx_render_analog.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest);
- if (omx_err != OMX_ErrorNone)
- {
-diff --git a/OMXAudio.h b/OMXAudio.h
-index 5b56e97..09d593d 100644
---- a/OMXAudio.h
-+++ b/OMXAudio.h
-@@ -46,6 +46,7 @@ public:
- COMXStreamInfo hints;
- bool use_thread;
- CStdString device;
-+ CStdString alsa_device;
- enum PCMLayout layout;
- bool boostOnDownmix;
- bool passthrough;
-diff --git a/OMXCore.cpp b/OMXCore.cpp
-index 9d5fe61..548ed2f 100644
---- a/OMXCore.cpp
-+++ b/OMXCore.cpp
-@@ -35,6 +35,7 @@
-
- #ifdef TARGET_LINUX
- #include "XMemUtils.h"
-+#include "OMXAlsa.h"
- #endif
-
- //#define OMX_DEBUG_EVENTS
-@@ -1429,6 +1430,11 @@ bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEX
- // Get video component handle setting up callbacks, component is in loaded state on return.
- if(!m_handle)
- {
-+#ifdef TARGET_LINUX
-+ if (strncmp("OMX.alsa.", component_name.c_str(), 9) == 0)
-+ omx_err = OMXALSA_GetHandle(&m_handle, (char*) component_name.c_str(), this, &m_callbacks);
-+ else
-+#endif
- omx_err = m_DllOMX->OMX_GetHandle(&m_handle, (char*)component_name.c_str(), this, &m_callbacks);
- if (!m_handle || omx_err != OMX_ErrorNone)
- {
-@@ -1505,6 +1511,11 @@ bool COMXCoreComponent::Deinitialize()
-
- CLog::Log(LOGDEBUG, "COMXCoreComponent::Deinitialize : %s handle %p\n",
- m_componentName.c_str(), m_handle);
-+#ifdef TARGET_LINUX
-+ if (strncmp("OMX.alsa.", m_componentName.c_str(), 9) == 0)
-+ omx_err = OMXALSA_FreeHandle(m_handle);
-+ else
-+#endif
- omx_err = m_DllOMX->OMX_FreeHandle(m_handle);
- if (omx_err != OMX_ErrorNone)
- {
-diff --git a/README.md b/README.md
-index 777de57..8c78ade 100644
---- a/README.md
-+++ b/README.md
-@@ -56,6 +56,7 @@ Usage: omxplayer [OPTIONS] [FILE]
- -k --keys Print key bindings
- -n --aidx index Audio stream index : e.g. 1
- -o --adev device Audio out device : e.g. hdmi/local/both
-+ -A --alsa device Use alsa device instead of BCM analog output
- -i --info Dump stream format and exit
- -I --with-info dump stream format before playback
- -s --stats Pts and buffer stats
-diff --git a/linux/OMXAlsa.cpp b/linux/OMXAlsa.cpp
-new file mode 100644
-index 0000000..6bac222
---- /dev/null
-+++ b/linux/OMXAlsa.cpp
-@@ -0,0 +1,1314 @@
-+/*
-+ * OMX IL Alsa Sink component
-+ * Copyright (c) 2016 Timo Teräs
-+ *
-+ * This Program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2, or (at your option)
-+ * any later version.
-+ *
-+ * TODO:
-+ * - timeouts for state transition failures
-+ */
-+
-+#include <stdio.h>
-+#include <stdint.h>
-+#include <stddef.h>
-+#include <string.h>
-+#include <stdlib.h>
-+#include <pthread.h>
-+#include <alsa/asoundlib.h>
-+#include <speex/speex_resampler.h>
-+#include <IL/OMX_Core.h>
-+#include <IL/OMX_Component.h>
-+#include <IL/OMX_Broadcom.h>
-+
-+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-+
-+struct _GOMX_COMMAND;
-+struct _GOMX_PORT;
-+struct _GOMX_COMPONENT;
-+
-+template <class X> static inline X max(X a, X b)
-+{
-+ return (a > b) ? a : b;
-+}
-+
-+template <class X> static OMX_ERRORTYPE omx_cast(X* &toptr, OMX_PTR fromptr)
-+{
-+ toptr = (X*) fromptr;
-+ if (toptr->nSize < sizeof(X)) return OMX_ErrorBadParameter;
-+ if (toptr->nVersion.nVersion != OMX_VERSION) return OMX_ErrorVersionMismatch;
-+ return OMX_ErrorNone;
-+}
-+
-+template <class X> static void omx_init(X &omx)
-+{
-+ omx.nSize = sizeof(X);
-+ omx.nVersion.nVersion = OMX_VERSION;
-+}
-+
-+#if 1
-+#include <utils/log.h>
-+#define CLOG(notice, comp, port, msg, ...) do { \
-+ struct _GOMX_PORT *_port = (struct _GOMX_PORT *) port; \
-+ if (_port) CLog::Log(notice ? LOGNOTICE : LOGDEBUG, "[%p port %d]: %s: " msg "\n", comp, _port->def.nPortIndex, __func__ , ##__VA_ARGS__); \
-+ else CLog::Log(notice ? LOGNOTICE : LOGDEBUG, "[%p] %s: " msg "\n", comp, __func__ , ##__VA_ARGS__); \
-+} while (0)
-+#else
-+#define CLOG(notice, comp, port, msg, ...) do { \
-+ struct _GOMX_PORT *_port = (struct _GOMX_PORT *) port; \
-+ if (_port) fprintf(stderr, "[%p port %d]: %s: " msg "\n", comp, _port->def.nPortIndex, __func__ , ##__VA_ARGS__); \
-+ else fprintf(stderr, "[%p] %s: " msg "\n", comp, __func__ , ##__VA_ARGS__); \
-+} while (0)
-+#endif
-+
-+#define CINFO(comp, port, msg, ...) CLOG(1, comp, port, msg , ##__VA_ARGS__)
-+#define CDEBUG(comp, port, msg, ...) CLOG(0, comp, port, msg , ##__VA_ARGS__)
-+
-+/* Generic OMX helpers */
-+
-+typedef struct _GOMX_QUEUE {
-+ void *head, *tail;
-+ ptrdiff_t offset;
-+ size_t num;
-+} GOMX_QUEUE;
-+
-+static void gomxq_init(GOMX_QUEUE *q, ptrdiff_t offset)
-+{
-+ q->head = q->tail = 0;
-+ q->offset = offset;
-+ q->num = 0;
-+}
-+
-+static void **gomxq_nextptr(GOMX_QUEUE *q, void *item)
-+{
-+ return (void**) ((uint8_t*)item + q->offset);
-+}
-+
-+static void gomxq_enqueue(GOMX_QUEUE *q, void *item)
-+{
-+ *gomxq_nextptr(q, item) = 0;
-+ if (q->tail) {
-+ *gomxq_nextptr(q, q->tail) = item;
-+ q->tail = item;
-+ } else {
-+ q->head = q->tail = item;
-+ }
-+ q->num++;
-+}
-+
-+static void *gomxq_dequeue(GOMX_QUEUE *q)
-+{
-+ void *item = q->head;
-+ if (item) {
-+ q->head = *gomxq_nextptr(q, item);
-+ if (!q->head) q->tail = 0;
-+ q->num--;
-+ }
-+ return item;
-+}
-+
-+typedef struct _GOMX_COMMAND {
-+ void *next;
-+ OMX_COMMANDTYPE cmd;
-+ OMX_U32 param;
-+ OMX_PTR data;
-+} GOMX_COMMAND;
-+
-+typedef struct _GOMX_PORT {
-+ OMX_BOOL new_enabled;
-+ OMX_PARAM_PORTDEFINITIONTYPE def;
-+
-+ size_t num_buffers, num_buffers_old;
-+ pthread_cond_t cond_no_buffers;
-+ pthread_cond_t cond_populated;
-+ pthread_cond_t cond_idle;
-+
-+ OMX_HANDLETYPE tunnel_comp;
-+ OMX_U32 tunnel_port;
-+ bool tunnel_supplier;
-+ GOMX_QUEUE tunnel_supplierq;
-+
-+ OMX_ERRORTYPE (*do_buffer)(struct _GOMX_COMPONENT *, struct _GOMX_PORT *, OMX_BUFFERHEADERTYPE *);
-+ OMX_ERRORTYPE (*flush)(struct _GOMX_COMPONENT *, struct _GOMX_PORT *);
-+} GOMX_PORT;
-+
-+typedef struct _GOMX_COMPONENT {
-+ OMX_COMPONENTTYPE omx;
-+ OMX_CALLBACKTYPE cb;
-+ OMX_STATETYPE state, wanted_state;
-+
-+ pthread_t component_thread, worker_thread;
-+ pthread_mutex_t mutex;
-+ pthread_cond_t cond;
-+
-+ const char *name;
-+ size_t nports;
-+ GOMX_PORT *ports;
-+ GOMX_QUEUE cmdq;
-+
-+ void* (*worker)(void *);
-+ OMX_ERRORTYPE (*statechange)(struct _GOMX_COMPONENT *);
-+} GOMX_COMPONENT;
-+
-+static GOMX_PORT *gomx_get_port(GOMX_COMPONENT *comp, size_t idx)
-+{
-+ if (idx < 0 || idx >= comp->nports) return 0;
-+ return &comp->ports[idx];
-+}
-+
-+OMX_ERRORTYPE gomx_get_component_version(
-+ OMX_HANDLETYPE hComponent, OMX_STRING pComponentName,
-+ OMX_VERSIONTYPE *pComponentVersion, OMX_VERSIONTYPE *pSpecVersion, OMX_UUIDTYPE *pComponentUUID)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ CDEBUG(comp, 0, "enter");
-+ strcpy(pComponentName, comp->name);
-+ pComponentVersion->nVersion = OMX_VERSION;
-+ pSpecVersion->nVersion = OMX_VERSION;
-+ memcpy(pComponentUUID, &hComponent, sizeof hComponent);
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE gomx_get_parameter(OMX_HANDLETYPE hComponent, OMX_INDEXTYPE nParamIndex, OMX_PTR pComponentParameterStructure)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ GOMX_PORT *port;
-+ OMX_PORT_PARAM_TYPE *ppt;
-+ OMX_PARAM_PORTDEFINITIONTYPE *pdt;
-+ OMX_ERRORTYPE r;
-+ OMX_PORTDOMAINTYPE domain;
-+
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+
-+ CDEBUG(comp, 0, "called %x, %p", nParamIndex, pComponentParameterStructure);
-+ switch (nParamIndex) {
-+ case OMX_IndexParamAudioInit:
-+ domain = OMX_PortDomainAudio;
-+ goto param_init;
-+ case OMX_IndexParamVideoInit:
-+ domain = OMX_PortDomainVideo;
-+ goto param_init;
-+ case OMX_IndexParamImageInit:
-+ domain = OMX_PortDomainImage;
-+ goto param_init;
-+ case OMX_IndexParamOtherInit:
-+ domain = OMX_PortDomainOther;
-+ goto param_init;
-+ param_init:
-+ if ((r = omx_cast(ppt, pComponentParameterStructure))) return r;
-+ ppt->nPorts = 0;
-+ ppt->nStartPortNumber = 0;
-+ for (size_t i = 0; i < comp->nports; i++) {
-+ if (comp->ports[i].def.eDomain != domain)
-+ continue;
-+ if (!ppt->nPorts)
-+ ppt->nStartPortNumber = i;
-+ ppt->nPorts++;
-+ }
-+ break;
-+ case OMX_IndexParamPortDefinition:
-+ if ((r = omx_cast(pdt, pComponentParameterStructure))) return r;
-+ if (!(port = gomx_get_port(comp, pdt->nPortIndex))) return OMX_ErrorBadPortIndex;
-+ memcpy(pComponentParameterStructure, &port->def, sizeof *pdt);
-+ break;
-+ default:
-+ CINFO(comp, 0, "UNSUPPORTED %x, %p", nParamIndex, pComponentParameterStructure);
-+ return OMX_ErrorNotImplemented;
-+ }
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE gomx_get_state(OMX_HANDLETYPE hComponent, OMX_STATETYPE *pState)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ *pState = comp->state;
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE gomx_component_tunnel_request(
-+ OMX_HANDLETYPE hComponent, OMX_U32 nPort,
-+ OMX_HANDLETYPE hTunneledComp, OMX_U32 nTunneledPort, OMX_TUNNELSETUPTYPE* pTunnelSetup)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ GOMX_PORT *port = 0;
-+
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+ if (!(port = gomx_get_port(comp, nPort))) return OMX_ErrorBadPortIndex;
-+ if (comp->state != OMX_StateLoaded && port->def.bEnabled)
-+ return OMX_ErrorIncorrectStateOperation;
-+
-+ if (hTunneledComp == 0 || pTunnelSetup == 0) {
-+ port->tunnel_comp = 0;
-+ return OMX_ErrorNone;
-+ }
-+
-+ if (port->def.eDir == OMX_DirInput) {
-+ /* Negotiate parameters */
-+ OMX_PARAM_PORTDEFINITIONTYPE param;
-+ omx_init(param);
-+ param.nPortIndex = nTunneledPort;
-+ if (OMX_GetParameter(hTunneledComp, OMX_IndexParamPortDefinition, &param))
-+ goto not_compatible;
-+ if (param.eDomain != port->def.eDomain)
-+ goto not_compatible;
-+
-+ param.nBufferCountActual = max(param.nBufferCountMin, port->def.nBufferCountMin);
-+ param.nBufferSize = max(port->def.nBufferSize, param.nBufferSize);
-+ param.nBufferAlignment = max(port->def.nBufferAlignment, param.nBufferAlignment);
-+ port->def.nBufferCountActual = param.nBufferCountActual;
-+ port->def.nBufferSize = param.nBufferSize;
-+ port->def.nBufferAlignment = param.nBufferAlignment;
-+ if (OMX_SetParameter(hTunneledComp, OMX_IndexParamPortDefinition, &param))
-+ goto not_compatible;
-+
-+ /* Negotiate buffer supplier */
-+ OMX_PARAM_BUFFERSUPPLIERTYPE suppl;
-+ omx_init(suppl);
-+ suppl.nPortIndex = nTunneledPort;
-+ if (OMX_GetParameter(hTunneledComp, OMX_IndexParamCompBufferSupplier, &suppl))
-+ goto not_compatible;
-+
-+ /* Being supplier is not supported so ask the other side to be it */
-+ suppl.eBufferSupplier =
-+ (pTunnelSetup->eSupplier == OMX_BufferSupplyOutput)
-+ ? OMX_BufferSupplyOutput : OMX_BufferSupplyInput;
-+ if (OMX_SetParameter(hTunneledComp, OMX_IndexParamCompBufferSupplier, &suppl))
-+ goto not_compatible;
-+
-+ port->tunnel_comp = hTunneledComp;
-+ port->tunnel_port = nTunneledPort;
-+ port->tunnel_supplier = (suppl.eBufferSupplier == OMX_BufferSupplyInput);
-+ pTunnelSetup->eSupplier = suppl.eBufferSupplier;
-+ CINFO(comp, port, "ComponentTunnnelRequest: %p %d", hTunneledComp, nTunneledPort);
-+ } else {
-+ CINFO(comp, port, "OUTPUT TUNNEL UNSUPPORTED: %p, %d, %p", hTunneledComp, nTunneledPort, pTunnelSetup);
-+ return OMX_ErrorNotImplemented;
-+ }
-+ return OMX_ErrorNone;
-+
-+not_compatible:
-+ CINFO(comp, port, "ComponentTunnnelRequest: %p %d - NOT COMPATIBLE", hTunneledComp, nTunneledPort);
-+ return OMX_ErrorPortsNotCompatible;
-+}
-+
-+static void __gomx_event(GOMX_COMPONENT *comp, OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
-+{
-+ if (!comp->cb.EventHandler) return;
-+ pthread_mutex_unlock(&comp->mutex);
-+ comp->cb.EventHandler((OMX_HANDLETYPE) comp, comp->omx.pApplicationPrivate, eEvent, nData1, nData2, pEventData);
-+ pthread_mutex_lock(&comp->mutex);
-+}
-+
-+static void __gomx_port_update_buffer_state(GOMX_COMPONENT *comp, GOMX_PORT *port)
-+{
-+ if (port->num_buffers_old == port->num_buffers)
-+ return;
-+
-+ port->def.bPopulated = (port->num_buffers >= port->def.nBufferCountActual) ? OMX_TRUE : OMX_FALSE;
-+ if (port->num_buffers == 0)
-+ pthread_cond_signal(&port->cond_no_buffers);
-+ else if (port->num_buffers == port->def.nBufferCountActual)
-+ pthread_cond_signal(&port->cond_populated);
-+}
-+
-+static OMX_ERRORTYPE gomx_use_buffer(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE **ppBufferHdr,
-+ OMX_U32 nPortIndex, OMX_PTR pAppPrivate, OMX_U32 nSizeBytes, OMX_U8* pBuffer)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ OMX_BUFFERHEADERTYPE *hdr;
-+ GOMX_PORT *port;
-+ void *buf;
-+
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+ if (!(port = gomx_get_port(comp, nPortIndex))) return OMX_ErrorBadPortIndex;
-+
-+ if (!((comp->state == OMX_StateLoaded && comp->wanted_state == OMX_StateIdle) ||
-+ (port->def.bEnabled == OMX_FALSE &&
-+ (comp->state == OMX_StateExecuting ||
-+ comp->state == OMX_StatePause ||
-+ comp->state == OMX_StateIdle))))
-+ return OMX_ErrorIncorrectStateOperation;
-+
-+ buf = malloc(sizeof(OMX_BUFFERHEADERTYPE) + (pBuffer ? 0 : nSizeBytes));
-+ if (!buf) return OMX_ErrorInsufficientResources;
-+
-+ hdr = (OMX_BUFFERHEADERTYPE *) buf;
-+ memset(hdr, 0, sizeof *hdr);
-+ omx_init(*hdr);
-+ hdr->pBuffer = pBuffer ? (OMX_U8*)pBuffer : (OMX_U8*)((char*)buf + nSizeBytes);
-+ hdr->nAllocLen = nSizeBytes;
-+ hdr->pAppPrivate = pAppPrivate;
-+ if (port->def.eDir == OMX_DirInput) {
-+ hdr->nInputPortIndex = nPortIndex;
-+ hdr->pOutputPortPrivate = pAppPrivate;
-+ } else {
-+ hdr->nOutputPortIndex = nPortIndex;
-+ hdr->pInputPortPrivate = pAppPrivate;
-+ }
-+ pthread_mutex_lock(&comp->mutex);
-+ port->num_buffers++;
-+ __gomx_port_update_buffer_state(comp, port);
-+ pthread_mutex_unlock(&comp->mutex);
-+
-+ CDEBUG(comp, port, "allocated: %d, %p, %u, %p", nPortIndex, pAppPrivate, nSizeBytes, pBuffer);
-+ *ppBufferHdr = hdr;
-+
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE gomx_allocate_buffer(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE **ppBufferHdr,
-+ OMX_U32 nPortIndex, OMX_PTR pAppPrivate, OMX_U32 nSizeBytes)
-+{
-+ return gomx_use_buffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, 0);
-+}
-+
-+static OMX_ERRORTYPE gomx_free_buffer(OMX_HANDLETYPE hComponent, OMX_U32 nPortIndex, OMX_BUFFERHEADERTYPE* pBuffer)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ GOMX_PORT *port;
-+
-+ if (!(port = gomx_get_port(comp, nPortIndex))) return OMX_ErrorBadPortIndex;
-+
-+ /* Freeing buffer is allowed in all states, so destructor can
-+ * synchronize successfully. */
-+
-+ pthread_mutex_lock(&comp->mutex);
-+
-+ if (!((comp->state == OMX_StateIdle && comp->wanted_state == OMX_StateLoaded) ||
-+ (port->def.bEnabled == OMX_FALSE &&
-+ (comp->state == OMX_StateExecuting ||
-+ comp->state == OMX_StatePause ||
-+ comp->state == OMX_StateIdle)))) {
-+ /* In unexpected states the port unpopulated error is sent. */
-+ if (port->num_buffers == port->def.nBufferCountActual)
-+ __gomx_event(comp, OMX_EventError, OMX_ErrorPortUnpopulated, nPortIndex, 0);
-+ /* FIXME? should we mark the port also down */
-+ }
-+
-+ port->num_buffers--;
-+ __gomx_port_update_buffer_state(comp, port);
-+
-+ pthread_mutex_unlock(&comp->mutex);
-+
-+ free(pBuffer);
-+
-+ return OMX_ErrorNone;
-+}
-+
-+static void __gomx_port_queue_supplier_buffer(GOMX_PORT *port, OMX_BUFFERHEADERTYPE *hdr)
-+{
-+ gomxq_enqueue(&port->tunnel_supplierq, (void *) hdr);
-+ if (port->tunnel_supplierq.num == port->num_buffers)
-+ pthread_cond_broadcast(&port->cond_idle);
-+}
-+
-+static OMX_ERRORTYPE __gomx_empty_buffer_done(GOMX_COMPONENT *comp, OMX_BUFFERHEADERTYPE *hdr)
-+{
-+ GOMX_PORT *port = gomx_get_port(comp, hdr->nInputPortIndex);
-+ OMX_ERRORTYPE r;
-+
-+ if (port->tunnel_comp) {
-+ /* Buffers are sent to the tunneled port once emptied as long as
-+ * the component is in the OMX_StateExecuting state */
-+ if ((comp->state == OMX_StateExecuting && port->def.bEnabled) ||
-+ !port->tunnel_supplier) {
-+ pthread_mutex_unlock(&comp->mutex);
-+ r = OMX_FillThisBuffer(port->tunnel_comp, hdr);
-+ pthread_mutex_lock(&comp->mutex);
-+ } else {
-+ r = OMX_ErrorIncorrectStateOperation;
-+ }
-+ } else {
-+ pthread_mutex_unlock(&comp->mutex);
-+ r = comp->cb.EmptyBufferDone((OMX_HANDLETYPE) comp, hdr->pAppPrivate, hdr);
-+ pthread_mutex_lock(&comp->mutex);
-+ }
-+
-+ if (r != OMX_ErrorNone && port->tunnel_supplier) {
-+ __gomx_port_queue_supplier_buffer(port, hdr);
-+ r = OMX_ErrorNone;
-+ }
-+
-+ return r;
-+}
-+
-+static OMX_ERRORTYPE gomx_empty_this_buffer(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ GOMX_PORT *port;
-+ OMX_ERRORTYPE r;
-+
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+ if (comp->state != OMX_StatePause && comp->state != OMX_StateExecuting &&
-+ comp->wanted_state != OMX_StateExecuting)
-+ return OMX_ErrorIncorrectStateOperation;
-+
-+ if (!(port = gomx_get_port(comp, pBuffer->nInputPortIndex)))
-+ return OMX_ErrorBadPortIndex;
-+
-+ pthread_mutex_lock(&comp->mutex);
-+ if (port->def.bEnabled) {
-+ if (port->do_buffer)
-+ r = port->do_buffer(comp, port, pBuffer);
-+ else
-+ r = __gomx_empty_buffer_done(comp, pBuffer);
-+ } else {
-+ if (port->tunnel_supplier) {
-+ __gomx_port_queue_supplier_buffer(port, pBuffer);
-+ r = OMX_ErrorNone;
-+ } else {
-+ r = OMX_ErrorIncorrectStateOperation;
-+ }
-+ }
-+ pthread_mutex_unlock(&comp->mutex);
-+ return r;
-+}
-+
-+static OMX_ERRORTYPE gomx_fill_this_buffer(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer)
-+{
-+ CDEBUG(hComponent, 0, "stub");
-+ return OMX_ErrorNotImplemented;
-+}
-+
-+static void __gomx_process_mark(GOMX_COMPONENT *comp, OMX_BUFFERHEADERTYPE *hdr)
-+{
-+ if (hdr->hMarkTargetComponent == (OMX_HANDLETYPE) comp) {
-+ __gomx_event(comp, OMX_EventMark, 0, 0, hdr->pMarkData);
-+ hdr->hMarkTargetComponent = 0;
-+ hdr->pMarkData = 0;
-+ }
-+}
-+
-+static OMX_ERRORTYPE __gomx_port_unpopulate(GOMX_COMPONENT *comp, GOMX_PORT *port)
-+{
-+ OMX_BUFFERHEADERTYPE *hdr;
-+ void *buf;
-+
-+ if (port->tunnel_supplier) {
-+ CINFO(comp, port, "waiting for supplier buffers (%d / %d)",
-+ (int)port->tunnel_supplierq.num, (int)port->num_buffers);
-+ while (port->tunnel_supplierq.num != port->num_buffers)
-+ pthread_cond_wait(&port->cond_idle, &comp->mutex);
-+
-+ CINFO(comp, port, "free tunnel buffers");
-+ while ((hdr = (OMX_BUFFERHEADERTYPE*)gomxq_dequeue(&port->tunnel_supplierq)) != 0) {
-+ buf = hdr->pBuffer;
-+ OMX_FreeBuffer(port->tunnel_comp, port->tunnel_port, hdr);
-+ free(buf);
-+ port->num_buffers--;
-+ __gomx_port_update_buffer_state(comp, port);
-+ }
-+ } else {
-+ /* Wait client / tunnel supplier to allocate buffers */
-+ CINFO(comp, port, "waiting %d buffers to be freed", (int)port->num_buffers);
-+ while (port->num_buffers > 0)
-+ pthread_cond_wait(&port->cond_no_buffers, &comp->mutex);
-+ }
-+
-+ CINFO(comp, port, "UNPOPULATED");
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE __gomx_port_populate(GOMX_COMPONENT *comp, GOMX_PORT *port)
-+{
-+ OMX_ERRORTYPE r;
-+ OMX_BUFFERHEADERTYPE *hdr;
-+ void *buf;
-+
-+ if (port->tunnel_supplier) {
-+ CINFO(comp, port, "Allocating tunnel buffers");
-+ while (port->num_buffers < port->def.nBufferCountActual) {
-+ pthread_mutex_unlock(&comp->mutex);
-+ r = OMX_ErrorInsufficientResources;
-+ buf = malloc(port->def.nBufferSize);
-+ if (buf) {
-+ r = OMX_UseBuffer(port->tunnel_comp, &hdr,
-+ port->tunnel_port, 0,
-+ port->def.nBufferSize, (OMX_U8*) buf);
-+ if (r != OMX_ErrorNone) free(buf);
-+ }
-+ if (r == OMX_ErrorInvalidState ||
-+ r == OMX_ErrorIncorrectStateOperation) {
-+ /* Non-supplier is not transitioned yet.
-+ * Wait for a bit and retry */
-+ usleep(1000);
-+ pthread_mutex_lock(&comp->mutex);
-+ continue;
-+ }
-+ pthread_mutex_lock(&comp->mutex);
-+
-+ if (r != OMX_ErrorNone) {
-+ /* Hard error. Cancel and bail out */
-+ __gomx_port_unpopulate(comp, port);
-+ return r;
-+ }
-+
-+ if (port->def.eDir == OMX_DirInput)
-+ hdr->nInputPortIndex = port->def.nPortIndex;
-+ else
-+ hdr->nOutputPortIndex = port->def.nPortIndex;
-+ gomxq_enqueue(&port->tunnel_supplierq, (void*) hdr);
-+ port->num_buffers++;
-+ __gomx_port_update_buffer_state(comp, port);
-+ }
-+ } else {
-+ /* Wait client / tunnel supplier to allocate buffers */
-+ CINFO(comp, port, "waiting buffers");
-+ while (!port->def.bPopulated)
-+ pthread_cond_wait(&port->cond_populated, &comp->mutex);
-+ }
-+
-+ CINFO(comp, port, "POPULATED");
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE gomx_send_command(OMX_HANDLETYPE hComponent, OMX_COMMANDTYPE Cmd, OMX_U32 nParam1, OMX_PTR pCmdData)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ GOMX_COMMAND *c;
-+
-+ /* OMX IL Specification is unclear which errors can be returned
-+ * inline and which need to be reported with a callback.
-+ * This just does minimal state checking, and queues everything
-+ * to worker and reports any real errors via the callback. */
-+ if (!hComponent) return OMX_ErrorInvalidComponent;
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+ if (!comp->cb.EventHandler) return OMX_ErrorNotReady;
-+
-+ c = (GOMX_COMMAND*) malloc(sizeof(GOMX_COMMAND));
-+ if (!c) return OMX_ErrorInsufficientResources;
-+
-+ CINFO(comp, 0, "SendCommand %x, %x, %p", Cmd, nParam1, pCmdData);
-+ c->cmd = Cmd;
-+ c->param = nParam1;
-+ c->data = pCmdData;
-+
-+ pthread_mutex_lock(&comp->mutex);
-+ gomxq_enqueue(&comp->cmdq, (void*) c);
-+ pthread_cond_signal(&comp->cond);
-+ pthread_mutex_unlock(&comp->mutex);
-+
-+ return OMX_ErrorNone;
-+}
-+
-+#define GOMX_TRANS(a,b) ((((uint32_t)a) << 16) | (uint32_t)b)
-+
-+static OMX_ERRORTYPE gomx_do_set_state(GOMX_COMPONENT *comp, GOMX_COMMAND *cmd)
-+{
-+ OMX_STATETYPE new_state = (OMX_STATETYPE) cmd->param;
-+ OMX_ERRORTYPE r;
-+ GOMX_PORT *port;
-+ size_t i;
-+
-+ if (comp->state == new_state) return OMX_ErrorSameState;
-+
-+ if (new_state == OMX_StateInvalid) {
-+ /* Transition to invalid state is always valid and immediate */
-+ comp->state = new_state;
-+ return OMX_ErrorNone;
-+ }
-+
-+ CDEBUG(comp, 0, "starting transition to state %d", new_state);
-+
-+ comp->wanted_state = new_state;
-+
-+ if (comp->statechange) {
-+ r = comp->statechange(comp);
-+ if (r != OMX_ErrorNone) goto err;
-+ }
-+
-+ switch (GOMX_TRANS(comp->state, new_state)) {
-+ case GOMX_TRANS(OMX_StateLoaded, OMX_StateIdle):
-+ /* populate or wait for all enabled ports to be populated */
-+ for (i = 0; i < comp->nports; i++) {
-+ if (!comp->ports[i].def.bEnabled) continue;
-+ r = __gomx_port_populate(comp, &comp->ports[i]);
-+ if (r) goto err;
-+ }
-+ break;
-+ case GOMX_TRANS(OMX_StateIdle, OMX_StateLoaded):
-+ /* free or wait all ports to be unpopulated */
-+ for (i = 0; i < comp->nports; i++) {
-+ r = __gomx_port_unpopulate(comp, &comp->ports[i]);
-+ if (r) goto err;
-+ }
-+ break;
-+ case GOMX_TRANS(OMX_StateIdle, OMX_StateExecuting):
-+ /* start threads */
-+ r = OMX_ErrorInsufficientResources;
-+ if (comp->worker &&
-+ pthread_create(&comp->worker_thread, 0, comp->worker, comp) != 0)
-+ goto err;
-+ break;
-+ case GOMX_TRANS(OMX_StateExecuting, OMX_StateIdle):
-+ /* stop/join threads & wait buffers to be returned to suppliers */
-+ if (comp->worker_thread) {
-+ pthread_mutex_unlock(&comp->mutex);
-+ pthread_join(comp->worker_thread, 0);
-+ pthread_mutex_lock(&comp->mutex);
-+ comp->worker_thread = 0;
-+ }
-+ for (i = 0; i < comp->nports; i++) {
-+ port = &comp->ports[i];
-+ if (!port->tunnel_supplier || !port->def.bEnabled) continue;
-+ while (port->tunnel_supplierq.num != port->num_buffers)
-+ pthread_cond_wait(&port->cond_idle, &comp->mutex);
-+ }
-+ break;
-+ default:
-+ /* FIXME: Pause and WaitForResources states not supported */
-+ r = OMX_ErrorIncorrectStateTransition;
-+ goto err;
-+ }
-+ comp->state = new_state;
-+ CDEBUG(comp, 0, "transition to state %d: success", new_state);
-+ return OMX_ErrorNone;
-+err:
-+ comp->wanted_state = comp->state;
-+ CDEBUG(comp, 0, "transition to state %d: result %x", new_state, r);
-+ return r;
-+}
-+
-+static OMX_ERRORTYPE gomx_do_port_command(GOMX_COMPONENT *comp, GOMX_PORT *port, GOMX_COMMAND *cmd)
-+{
-+ OMX_ERRORTYPE r = OMX_ErrorNone;
-+
-+ switch (cmd->cmd) {
-+ case OMX_CommandFlush:
-+ if (port->flush) r = port->flush(comp, port);
-+ break;
-+ case OMX_CommandPortEnable:
-+ port->def.bEnabled = OMX_TRUE;
-+ r = __gomx_port_populate(comp, port);
-+ if (r != OMX_ErrorNone)
-+ port->def.bEnabled = OMX_FALSE;
-+ break;
-+ case OMX_CommandPortDisable:
-+ port->def.bEnabled = OMX_FALSE;
-+ if (port->flush) port->flush(comp, port);
-+ r = __gomx_port_unpopulate(comp, port);
-+ break;
-+ default:
-+ r = OMX_ErrorNotImplemented;
-+ break;
-+ }
-+ return r;
-+}
-+
-+static OMX_ERRORTYPE gomx_do_command(GOMX_COMPONENT *comp, GOMX_COMMAND *cmd)
-+{
-+ GOMX_PORT *port;
-+
-+ switch (cmd->cmd) {
-+ case OMX_CommandStateSet:
-+ CINFO(comp, 0, "state %x", cmd->param);
-+ return gomx_do_set_state(comp, cmd);
-+ case OMX_CommandFlush:
-+ case OMX_CommandPortEnable:
-+ case OMX_CommandPortDisable:
-+ /* FIXME: OMX_ALL is not supported (but not used in omxplayer) */
-+ if (!(port = gomx_get_port(comp, cmd->param)))
-+ return OMX_ErrorBadPortIndex;
-+ CINFO(comp, port, "command %x", cmd->cmd);
-+ return gomx_do_port_command(comp, port, cmd);
-+ case OMX_CommandMarkBuffer:
-+ /* FIXME: Not implemented (but not used in omxplayer) */
-+ default:
-+ CINFO(comp, 0, "UNSUPPORTED %x, %x, %p", cmd->cmd, cmd->param, cmd->data);
-+ return OMX_ErrorNotImplemented;
-+ }
-+}
-+
-+static void *gomx_worker(void *ptr)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) ptr;
-+ GOMX_PORT *port;
-+ GOMX_COMMAND *cmd;
-+ OMX_BUFFERHEADERTYPE *hdr;
-+ OMX_ERRORTYPE r;
-+
-+ CINFO(comp, 0, "start");
-+ pthread_mutex_lock(&comp->mutex);
-+ while (comp->state != OMX_StateInvalid) {
-+ cmd = (GOMX_COMMAND *) gomxq_dequeue(&comp->cmdq);
-+ if (cmd) {
-+ r = gomx_do_command(comp, cmd);
-+ if (r == OMX_ErrorNone)
-+ __gomx_event(comp, OMX_EventCmdComplete,
-+ cmd->cmd, cmd->param, cmd->data);
-+ else
-+ __gomx_event(comp, OMX_EventError, r, 0, 0);
-+ } else {
-+ pthread_cond_wait(&comp->cond, &comp->mutex);
-+ }
-+
-+ if (comp->state != OMX_StateExecuting)
-+ continue;
-+
-+ /* FIXME: Rate limit and retry if needed suppplier buffer enqueuing */
-+ for (size_t i = 0; i < comp->nports; i++) {
-+ port = &comp->ports[i];
-+ while ((hdr = (OMX_BUFFERHEADERTYPE*)gomxq_dequeue(&port->tunnel_supplierq)) != 0) {
-+ pthread_mutex_unlock(&comp->mutex);
-+ r = OMX_FillThisBuffer(port->tunnel_comp, hdr);
-+ pthread_mutex_lock(&comp->mutex);
-+ if (r != OMX_ErrorNone) {
-+ __gomx_port_queue_supplier_buffer(port, hdr);
-+ break;
-+ }
-+ }
-+ }
-+ }
-+ pthread_mutex_unlock(&comp->mutex);
-+ /* FIXME: make sure all buffers are returned and worker threads stopped */
-+ CINFO(comp, 0, "stop");
-+ return 0;
-+}
-+
-+static OMX_ERRORTYPE gomx_set_callbacks(OMX_HANDLETYPE hComponent, OMX_CALLBACKTYPE* pCallbacks, OMX_PTR pAppData)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+ if (comp->state != OMX_StateLoaded) return OMX_ErrorIncorrectStateOperation;
-+ pthread_mutex_lock(&comp->mutex);
-+ comp->omx.pApplicationPrivate = pAppData;
-+ comp->cb = *pCallbacks;
-+ pthread_mutex_unlock(&comp->mutex);
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE gomx_use_egl_image(OMX_HANDLETYPE hComponent,
-+ OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex,
-+ OMX_PTR pAppPrivate, void* eglImage)
-+{
-+ return OMX_ErrorNotImplemented;
-+}
-+
-+static OMX_ERRORTYPE gomx_component_role_enum(OMX_HANDLETYPE hComponent, OMX_U8 *cRole, OMX_U32 nIndex)
-+{
-+ return OMX_ErrorNotImplemented;
-+}
-+
-+static void gomx_init(GOMX_COMPONENT *comp, const char *name, OMX_PTR pAppData, OMX_CALLBACKTYPE* pCallbacks, GOMX_PORT *ports, size_t nports)
-+{
-+ comp->omx.nSize = sizeof comp->omx;
-+ comp->omx.nVersion.nVersion = OMX_VERSION;
-+ comp->omx.pApplicationPrivate = pAppData;
-+ comp->omx.GetComponentVersion = gomx_get_component_version;
-+ comp->omx.SendCommand = gomx_send_command;
-+ comp->omx.GetParameter = gomx_get_parameter;
-+ comp->omx.GetState = gomx_get_state;
-+ comp->omx.ComponentTunnelRequest = gomx_component_tunnel_request;
-+ comp->omx.UseBuffer = gomx_use_buffer;
-+ comp->omx.AllocateBuffer = gomx_allocate_buffer;
-+ comp->omx.FreeBuffer = gomx_free_buffer;
-+ comp->omx.EmptyThisBuffer = gomx_empty_this_buffer;
-+ comp->omx.FillThisBuffer = gomx_fill_this_buffer;
-+ comp->omx.SetCallbacks = gomx_set_callbacks;
-+ comp->omx.UseEGLImage = gomx_use_egl_image;
-+ comp->omx.ComponentRoleEnum = gomx_component_role_enum;
-+
-+ comp->name = name;
-+ comp->cb = *pCallbacks;
-+ comp->state = OMX_StateLoaded;
-+ comp->nports = nports;
-+ comp->ports = ports;
-+
-+ gomxq_init(&comp->cmdq, offsetof(GOMX_COMMAND, next));
-+ pthread_cond_init(&comp->cond, 0);
-+ pthread_mutex_init(&comp->mutex, 0);
-+ pthread_create(&comp->component_thread, 0, gomx_worker, comp);
-+
-+ for (size_t i = 0; i < comp->nports; i++) {
-+ GOMX_PORT *port = &comp->ports[i];
-+ pthread_cond_init(&port->cond_no_buffers, 0);
-+ pthread_cond_init(&port->cond_populated, 0);
-+ pthread_cond_init(&port->cond_idle, 0);
-+ gomxq_init(&port->tunnel_supplierq,
-+ port->def.eDir == OMX_DirInput
-+ ? offsetof(OMX_BUFFERHEADERTYPE, pInputPortPrivate)
-+ : offsetof(OMX_BUFFERHEADERTYPE, pOutputPortPrivate));
-+ }
-+}
-+
-+static void gomx_fini(GOMX_COMPONENT *comp)
-+{
-+ CINFO(comp, 0, "destroying");
-+ pthread_mutex_lock(&comp->mutex);
-+ comp->state = OMX_StateInvalid;
-+ pthread_cond_broadcast(&comp->cond);
-+ pthread_mutex_unlock(&comp->mutex);
-+ pthread_join(comp->component_thread, 0);
-+
-+ for (size_t i = 0; i < comp->nports; i++) {
-+ GOMX_PORT *port = &comp->ports[i];
-+ pthread_cond_destroy(&port->cond_no_buffers);
-+ pthread_cond_destroy(&port->cond_populated);
-+ pthread_cond_destroy(&port->cond_idle);
-+ }
-+ pthread_mutex_destroy(&comp->mutex);
-+ pthread_cond_destroy(&comp->cond);
-+}
-+
-+/* ALSA Sink OMX Component */
-+
-+#define OMXALSA_PORT_AUDIO 0
-+#define OMXALSA_PORT_CLOCK 1
-+
-+typedef struct _OMX_ALSASINK {
-+ GOMX_COMPONENT gcomp;
-+ GOMX_PORT port_data[2];
-+ GOMX_QUEUE playq;
-+ pthread_cond_t cond_play;
-+ size_t frame_size, sample_rate, play_queue_size;
-+ int64_t starttime;
-+ int32_t timescale;
-+ OMX_AUDIO_PARAM_PCMMODETYPE pcm;
-+ snd_pcm_format_t pcm_format;
-+ char device_name[16];
-+} OMX_ALSASINK;
-+
-+static OMX_ERRORTYPE omxalsasink_set_parameter(OMX_HANDLETYPE hComponent, OMX_INDEXTYPE nParamIndex, OMX_PTR pComponentParameterStructure)
-+{
-+ static const struct {
-+ snd_pcm_format_t fmt;
-+ unsigned char pcm_mode;
-+ unsigned char bits_per_sample;
-+ unsigned char numerical_data;
-+ unsigned char endianess;
-+ } fmtmap[] = {
-+ { SND_PCM_FORMAT_S8, OMX_AUDIO_PCMModeLinear, 8, OMX_NumericalDataSigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_U8, OMX_AUDIO_PCMModeLinear, 8, OMX_NumericalDataUnsigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_S16_LE, OMX_AUDIO_PCMModeLinear, 16, OMX_NumericalDataSigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_U16_LE, OMX_AUDIO_PCMModeLinear, 16, OMX_NumericalDataUnsigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_S16_BE, OMX_AUDIO_PCMModeLinear, 16, OMX_NumericalDataSigned, OMX_EndianBig },
-+ { SND_PCM_FORMAT_U16_BE, OMX_AUDIO_PCMModeLinear, 16, OMX_NumericalDataUnsigned, OMX_EndianBig },
-+ { SND_PCM_FORMAT_S24_LE, OMX_AUDIO_PCMModeLinear, 24, OMX_NumericalDataSigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_U24_LE, OMX_AUDIO_PCMModeLinear, 24, OMX_NumericalDataUnsigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_S24_BE, OMX_AUDIO_PCMModeLinear, 24, OMX_NumericalDataSigned, OMX_EndianBig },
-+ { SND_PCM_FORMAT_U24_BE, OMX_AUDIO_PCMModeLinear, 24, OMX_NumericalDataUnsigned, OMX_EndianBig },
-+ { SND_PCM_FORMAT_S32_LE, OMX_AUDIO_PCMModeLinear, 32, OMX_NumericalDataSigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_U32_LE, OMX_AUDIO_PCMModeLinear, 32, OMX_NumericalDataUnsigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_S32_BE, OMX_AUDIO_PCMModeLinear, 32, OMX_NumericalDataSigned, OMX_EndianBig },
-+ { SND_PCM_FORMAT_U32_BE, OMX_AUDIO_PCMModeLinear, 32, OMX_NumericalDataUnsigned, OMX_EndianBig },
-+ { SND_PCM_FORMAT_A_LAW, OMX_AUDIO_PCMModeALaw, 8, OMX_NumericalDataUnsigned, OMX_EndianLittle },
-+ { SND_PCM_FORMAT_MU_LAW, OMX_AUDIO_PCMModeMULaw, 8, OMX_NumericalDataUnsigned, OMX_EndianLittle },
-+ };
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) hComponent;
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ GOMX_PORT *port;
-+ OMX_AUDIO_PARAM_PCMMODETYPE *pmt;
-+ OMX_ERRORTYPE r;
-+ snd_pcm_format_t pcm_format = SND_PCM_FORMAT_UNKNOWN;
-+
-+ /* Valid in OMX_StateLoaded or on disabled port... so can't check
-+ * state without port number which is in index specific struct. */
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+
-+ switch (nParamIndex) {
-+ case OMX_IndexParamAudioPcm:
-+ if ((r = omx_cast(pmt, pComponentParameterStructure))) return r;
-+ if (!(port = gomx_get_port(comp, pmt->nPortIndex))) return OMX_ErrorBadPortIndex;
-+ if (pmt->nPortIndex != OMXALSA_PORT_AUDIO) return OMX_ErrorBadParameter;
-+
-+ if (comp->state != OMX_StateLoaded && port->def.bEnabled)
-+ return OMX_ErrorIncorrectStateOperation;
-+
-+ for (size_t i = 0; i < ARRAY_SIZE(fmtmap); i++) {
-+ if (fmtmap[i].pcm_mode == pmt->ePCMMode &&
-+ fmtmap[i].bits_per_sample == pmt->nBitPerSample &&
-+ fmtmap[i].numerical_data == pmt->eNumData &&
-+ fmtmap[i].endianess == pmt->eEndian) {
-+ pcm_format = fmtmap[i].fmt;
-+ break;
-+ }
-+ }
-+ if (pcm_format == SND_PCM_FORMAT_UNKNOWN)
-+ return OMX_ErrorBadParameter;
-+
-+ memcpy(&sink->pcm, pmt, sizeof *pmt);
-+ sink->pcm_format = pcm_format;
-+ break;
-+ default:
-+ CINFO(comp, 0, "UNSUPPORTED %x, %p", nParamIndex, pComponentParameterStructure);
-+ return OMX_ErrorNotImplemented;
-+ }
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_get_config(OMX_HANDLETYPE hComponent, OMX_INDEXTYPE nIndex, OMX_PTR pComponentConfigStructure)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) hComponent;
-+ OMX_PARAM_U32TYPE *u32param;
-+ OMX_ERRORTYPE r;
-+
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+
-+ switch (nIndex) {
-+ case OMX_IndexConfigAudioRenderingLatency:
-+ if ((r = omx_cast(u32param, pComponentConfigStructure))) return r;
-+ /* Number of samples received but not played */
-+ pthread_mutex_lock(&comp->mutex);
-+ if (sink->frame_size)
-+ u32param->nU32 = sink->play_queue_size / sink->frame_size;
-+ else
-+ u32param->nU32 = 0;
-+ pthread_mutex_unlock(&comp->mutex);
-+ CDEBUG(comp, 0, "OMX_IndexConfigAudioRenderingLatency %d", u32param->nU32);
-+ break;
-+ default:
-+ CINFO(comp, 0, "UNSUPPORTED %x, %p", nIndex, pComponentConfigStructure);
-+ return OMX_ErrorNotImplemented;
-+ }
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_set_config(OMX_HANDLETYPE hComponent, OMX_INDEXTYPE nIndex, OMX_PTR pComponentConfigStructure)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT*) hComponent;
-+ OMX_ALSASINK *sink = (OMX_ALSASINK*) hComponent;
-+ OMX_CONFIG_BOOLEANTYPE *bt;
-+ OMX_CONFIG_BRCMAUDIODESTINATIONTYPE *adest;
-+ OMX_ERRORTYPE r;
-+
-+ if (comp->state == OMX_StateInvalid) return OMX_ErrorInvalidState;
-+
-+ switch (nIndex) {
-+ case OMX_IndexConfigBrcmClockReferenceSource:
-+ if ((r = omx_cast(bt, pComponentConfigStructure))) return r;
-+ CDEBUG(comp, 0, "OMX_IndexConfigBrcmClockReferenceSource %d", bt->bEnabled);
-+ break;
-+ case OMX_IndexConfigBrcmAudioDestination:
-+ if ((r = omx_cast(adest, pComponentConfigStructure))) return r;
-+ strlcpy(sink->device_name, (const char*) adest->sName, sizeof sink->device_name);
-+ CDEBUG(comp, 0, "OMX_IndexConfigBrcmAudioDestination %s", adest->sName);
-+ break;
-+ default:
-+ CINFO(comp, 0, "UNSUPPORTED %x, %p", nIndex, pComponentConfigStructure);
-+ return OMX_ErrorNotImplemented;
-+ }
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_get_extension_index(OMX_HANDLETYPE hComponent, OMX_STRING cParameterName, OMX_INDEXTYPE *pIndexType)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) hComponent;
-+ CINFO(comp, 0, "UNSUPPORTED '%s', %p", cParameterName, pIndexType);
-+ return OMX_ErrorNotImplemented;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_deinit(OMX_HANDLETYPE hComponent)
-+{
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) hComponent;
-+ gomx_fini(&sink->gcomp);
-+ free(sink);
-+ return OMX_ErrorNone;
-+}
-+
-+static void *omxalsasink_worker(void *ptr)
-+{
-+ GOMX_COMPONENT *comp = (GOMX_COMPONENT *) ptr;
-+ OMX_HANDLETYPE hComponent = (OMX_HANDLETYPE) comp;
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) hComponent;
-+ OMX_BUFFERHEADERTYPE *buf;
-+ GOMX_PORT *audio_port = &comp->ports[OMXALSA_PORT_AUDIO];
-+ GOMX_PORT *clock_port = &comp->ports[OMXALSA_PORT_CLOCK];
-+ snd_pcm_t *dev = 0;
-+ snd_pcm_sframes_t n;
-+ snd_pcm_hw_params_t *hwp;
-+ snd_pcm_uframes_t buffer_size, period_size, period_size_max;
-+ SpeexResamplerState *resampler = 0;
-+ spx_int16_t *resample_buf = 0;
-+ size_t resample_bufsz;
-+ unsigned int rate;
-+ int32_t timescale;
-+ int err;
-+
-+ CINFO(comp, 0, "worker started");
-+
-+ err = snd_pcm_open(&dev, sink->device_name, SND_PCM_STREAM_PLAYBACK, 0);
-+ if (err < 0) goto alsa_error;
-+
-+ rate = sink->pcm.nSamplingRate;
-+ buffer_size = rate / 5;
-+ period_size = buffer_size / 4;
-+ period_size_max = buffer_size / 3;
-+
-+ snd_pcm_hw_params_alloca(&hwp);
-+ snd_pcm_hw_params_any(dev, hwp);
-+ err = snd_pcm_hw_params_set_channels(dev, hwp, sink->pcm.nChannels);
-+ if (err) goto alsa_error;
-+ err = snd_pcm_hw_params_set_access(dev, hwp, sink->pcm.bInterleaved ? SND_PCM_ACCESS_RW_INTERLEAVED : SND_PCM_ACCESS_RW_NONINTERLEAVED);
-+ if (err) goto alsa_error;
-+ err = snd_pcm_hw_params_set_rate_near(dev, hwp, &rate, 0);
-+ if (err) goto alsa_error;
-+ err = snd_pcm_hw_params_set_format(dev, hwp, sink->pcm_format);
-+ if (err) goto alsa_error;
-+ err = snd_pcm_hw_params_set_period_size_max(dev, hwp, &period_size_max, 0);
-+ if (err) goto alsa_error;
-+ err = snd_pcm_hw_params_set_buffer_size_near(dev, hwp, &buffer_size);
-+ if (err) goto alsa_error;
-+ err = snd_pcm_hw_params_set_period_size_near(dev, hwp, &period_size, 0);
-+ if (err) goto alsa_error;
-+ err = snd_pcm_hw_params(dev, hwp);
-+ if (err) goto alsa_error;
-+
-+ err = snd_pcm_prepare(dev);
-+ if (err < 0) goto alsa_error;
-+
-+ sink->pcm.nSamplingRate = rate;
-+ sink->frame_size = (sink->pcm.nChannels * sink->pcm.nBitPerSample) >> 3;
-+ sink->sample_rate = rate;
-+
-+ resampler = speex_resampler_init(sink->pcm.nChannels, rate, rate, 1, 0);
-+ if (!resampler) goto err;
-+
-+ resample_bufsz = audio_port->def.nBufferSize * 2;
-+ resample_buf = (spx_int16_t *) malloc(resample_bufsz);
-+ if (!resample_buf) goto err;
-+
-+ CINFO(comp, 0, "sample_rate %d, frame_size %d", rate, sink->frame_size);
-+
-+ pthread_mutex_lock(&comp->mutex);
-+ while (comp->wanted_state == OMX_StateExecuting) {
-+ buf = 0;
-+ if (sink->timescale)
-+ buf = (OMX_BUFFERHEADERTYPE*) gomxq_dequeue(&sink->playq);
-+ if (!buf) {
-+ pthread_cond_wait(&sink->cond_play, &comp->mutex);
-+ continue;
-+ }
-+
-+ if (resampler && timescale != sink->timescale) {
-+ int in_rate = (int64_t)rate * sink->timescale >> 16;
-+ timescale = sink->timescale;
-+ if (timescale > 0x20000) timescale = 0x20000;
-+ CDEBUG(comp, 0, "resampler: %d -> %d", in_rate, rate);
-+ speex_resampler_set_rate(resampler, in_rate, rate);
-+ }
-+
-+ sink->play_queue_size -= buf->nFilledLen;
-+ if (clock_port->tunnel_comp && !(buf->nFlags & OMX_BUFFERFLAG_TIME_UNKNOWN)) {
-+ OMX_TIME_CONFIG_TIMESTAMPTYPE tst;
-+ int64_t pts = omx_ticks_to_s64(buf->nTimeStamp);
-+ snd_pcm_sframes_t delay = 0;
-+
-+ omx_init(tst);
-+ tst.nPortIndex = clock_port->tunnel_port;
-+ tst.nTimestamp = buf->nTimeStamp;
-+ if (resampler && buf->nFlags & OMX_BUFFERFLAG_STARTTIME)
-+ speex_resampler_reset_mem(resampler);
-+ if (buf->nFlags & (OMX_BUFFERFLAG_STARTTIME|OMX_BUFFERFLAG_DISCONTINUITY)) {
-+ CINFO(comp, 0, "STARTTIME nTimeStamp=%llx", pts);
-+ sink->starttime = pts;
-+ }
-+
-+ snd_pcm_delay(dev, &delay);
-+ if (resampler)
-+ delay += speex_resampler_get_input_latency(resampler);
-+
-+ pts -= (int64_t)delay * OMX_TICKS_PER_SECOND / sink->sample_rate;
-+
-+ pthread_mutex_unlock(&comp->mutex);
-+ if (buf->nFlags & (OMX_BUFFERFLAG_STARTTIME|OMX_BUFFERFLAG_DISCONTINUITY))
-+ OMX_SetConfig(clock_port->tunnel_comp, OMX_IndexConfigTimeClientStartTime, &tst);
-+ if (pts >= sink->starttime) {
-+ tst.nTimestamp = omx_ticks_from_s64(pts);
-+ OMX_SetConfig(clock_port->tunnel_comp, OMX_IndexConfigTimeCurrentAudioReference, &tst);
-+ }
-+ pthread_mutex_lock(&comp->mutex);
-+ }
-+
-+ if (buf->nFlags & (OMX_BUFFERFLAG_DECODEONLY|OMX_BUFFERFLAG_CODECCONFIG|OMX_BUFFERFLAG_DATACORRUPT)) {
-+ CDEBUG(comp, 0, "skipping: %d bytes, flags %x", buf->nFilledLen, buf->nFlags);
-+ } else {
-+ spx_int16_t *in_ptr;
-+ uint8_t *out_ptr;
-+ spx_uint32_t in_len, out_len;
-+
-+ pthread_mutex_unlock(&comp->mutex);
-+
-+ in_ptr = (spx_int16_t *)(buf->pBuffer + buf->nOffset);
-+ in_len = buf->nFilledLen / sink->frame_size;
-+
-+ if (resampler) {
-+ out_len = resample_bufsz / sink->frame_size;
-+ speex_resampler_process_interleaved_int(
-+ resampler,
-+ in_ptr, &in_len,
-+ resample_buf, &out_len);
-+ out_ptr = (uint8_t *) resample_buf;
-+ } else {
-+ out_ptr = (uint8_t *) in_ptr;
-+ out_len = in_len;
-+ }
-+
-+ while (out_len > 0) {
-+ n = snd_pcm_writei(dev, out_ptr, out_len);
-+ if (n < 0) {
-+ CINFO(comp, 0, "alsa error: %ld: %s", n, snd_strerror(n));
-+ snd_pcm_prepare(dev);
-+ n = 0;
-+ }
-+ out_len -= n;
-+ n *= sink->frame_size;
-+ out_ptr += n;
-+ }
-+ pthread_mutex_lock(&comp->mutex);
-+ }
-+
-+ __gomx_process_mark(comp, buf);
-+ if (buf->nFlags & OMX_BUFFERFLAG_EOS) {
-+ CDEBUG(comp, 0, "end-of-stream");
-+ __gomx_event(comp, OMX_EventBufferFlag, OMXALSA_PORT_AUDIO, buf->nFlags, 0);
-+ }
-+ __gomx_empty_buffer_done(comp, buf);
-+ }
-+ pthread_mutex_unlock(&comp->mutex);
-+cleanup:
-+ if (dev) snd_pcm_close(dev);
-+ if (resampler) speex_resampler_destroy(resampler);
-+ free(resample_buf);
-+ CINFO(comp, 0, "worker stopped");
-+ return 0;
-+
-+alsa_error:
-+ CINFO(comp, 0, "ALSA error: %s", snd_strerror(err));
-+err:
-+ pthread_mutex_lock(&comp->mutex);
-+ /* FIXME: Current we just go to invalid state, but we might go
-+ * back to Idle with ErrorResourcesPreempted and let the client
-+ * recover. However, omxplayer does not care about this. */
-+ comp->state = OMX_StateInvalid;
-+ __gomx_event(comp, OMX_EventError, OMX_StateInvalid, 0, 0);
-+ pthread_mutex_unlock(&comp->mutex);
-+ goto cleanup;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_audio_do_buffer(GOMX_COMPONENT *comp, GOMX_PORT *port, OMX_BUFFERHEADERTYPE *buf)
-+{
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) comp;
-+ sink->play_queue_size += buf->nFilledLen;
-+ gomxq_enqueue(&sink->playq, (void *) buf);
-+ pthread_cond_signal(&sink->cond_play);
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_audio_flush(GOMX_COMPONENT *comp, GOMX_PORT *port)
-+{
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) comp;
-+ OMX_BUFFERHEADERTYPE *buf;
-+ while ((buf = (OMX_BUFFERHEADERTYPE *) gomxq_dequeue(&sink->playq)) != 0) {
-+ sink->play_queue_size -= buf->nFilledLen;
-+ __gomx_empty_buffer_done(comp, buf);
-+ }
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_clock_do_buffer(GOMX_COMPONENT *comp, GOMX_PORT *port, OMX_BUFFERHEADERTYPE *buf)
-+{
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) comp;
-+ OMX_TIME_MEDIATIMETYPE *pMediaTime;
-+ int wake = 0;
-+
-+ if (omx_cast(pMediaTime, buf->pBuffer) == OMX_ErrorNone) {
-+ CDEBUG(comp, port, "%p: clock %u bytes, flags=%x, nTimeStamp=%llx, eState=%d, xScale=%x",
-+ buf, buf->nFilledLen, buf->nFlags, omx_ticks_to_s64(buf->nTimeStamp),
-+ pMediaTime->eState, pMediaTime->xScale);
-+ wake = (!sink->timescale && pMediaTime->xScale);
-+ sink->timescale = pMediaTime->xScale;
-+ } else {
-+ CDEBUG(comp, port, "%p: clock %u bytes, flags=%x, nTimeStamp=%llx",
-+ buf, buf->nFilledLen, buf->nFlags, omx_ticks_to_s64(buf->nTimeStamp));
-+ }
-+ __gomx_process_mark(comp, buf);
-+ __gomx_empty_buffer_done(comp, buf);
-+ if (wake) pthread_cond_signal(&sink->cond_play);
-+
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_statechange(GOMX_COMPONENT *comp)
-+{
-+ OMX_ALSASINK *sink = (OMX_ALSASINK *) comp;
-+ pthread_cond_signal(&sink->cond_play);
-+ return OMX_ErrorNone;
-+}
-+
-+static OMX_ERRORTYPE omxalsasink_create(OMX_HANDLETYPE *pHandle, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallbacks)
-+{
-+ OMX_ALSASINK *sink;
-+ GOMX_PORT *port;
-+
-+ sink = (OMX_ALSASINK *) calloc(1, sizeof *sink);
-+ if (!sink) return OMX_ErrorInsufficientResources;
-+
-+ strlcpy(sink->device_name, "default", sizeof sink->device_name);
-+ gomxq_init(&sink->playq, offsetof(OMX_BUFFERHEADERTYPE, pInputPortPrivate));
-+
-+ /* Audio port */
-+ port = &sink->port_data[OMXALSA_PORT_AUDIO];
-+ port->def.nSize = sizeof *port;
-+ port->def.nVersion.nVersion = OMX_VERSION;
-+ port->def.nPortIndex = OMXALSA_PORT_AUDIO;
-+ port->def.eDir = OMX_DirInput;
-+ port->def.nBufferCountMin = 4;
-+ port->def.nBufferCountActual = 4;
-+ port->def.nBufferSize = 8 * 1024;
-+ port->def.bEnabled = OMX_TRUE;
-+ port->def.eDomain = OMX_PortDomainAudio;
-+ port->def.format.audio.cMIMEType = (char *) "raw/audio";
-+ port->def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
-+ port->def.nBufferAlignment = 4;
-+ port->do_buffer = omxalsasink_audio_do_buffer;
-+ port->flush = omxalsasink_audio_flush;
-+
-+ /* Clock port */
-+ port = &sink->port_data[OMXALSA_PORT_CLOCK];
-+ port->def.nSize = sizeof *port;
-+ port->def.nVersion.nVersion = OMX_VERSION;
-+ port->def.nPortIndex = OMXALSA_PORT_CLOCK;
-+ port->def.eDir = OMX_DirInput;
-+ port->def.nBufferCountMin = 1;
-+ port->def.nBufferCountActual = 1;
-+ port->def.nBufferSize = sizeof(OMX_TIME_MEDIATIMETYPE);
-+ port->def.bEnabled = OMX_TRUE;
-+ port->def.eDomain = OMX_PortDomainOther;
-+ port->def.format.other.eFormat = OMX_OTHER_FormatTime;
-+ port->def.nBufferAlignment = 4;
-+ port->do_buffer = omxalsasink_clock_do_buffer;
-+
-+ gomx_init(&sink->gcomp, "OMX.alsa.audio_render", pAppData, pCallbacks, sink->port_data, ARRAY_SIZE(sink->port_data));
-+ sink->gcomp.omx.SetParameter = omxalsasink_set_parameter;
-+ sink->gcomp.omx.GetConfig = omxalsasink_get_config;
-+ sink->gcomp.omx.SetConfig = omxalsasink_set_config;
-+ sink->gcomp.omx.GetExtensionIndex = omxalsasink_get_extension_index;
-+ sink->gcomp.omx.ComponentDeInit = omxalsasink_deinit;
-+ sink->gcomp.worker = omxalsasink_worker;
-+ sink->gcomp.statechange = omxalsasink_statechange;
-+ pthread_cond_init(&sink->cond_play, 0);
-+
-+ *pHandle = (OMX_HANDLETYPE) sink;
-+ return OMX_ErrorNone;
-+}
-+
-+/* OMX Glue to get the handle */
-+
-+#include <OMXAlsa.h>
-+
-+OMX_ERRORTYPE OMXALSA_GetHandle(OMX_OUT OMX_HANDLETYPE* pHandle, OMX_IN OMX_STRING cComponentName,
-+ OMX_IN OMX_PTR pAppData, OMX_IN OMX_CALLBACKTYPE* pCallbacks)
-+{
-+ if (strcmp(cComponentName, "OMX.alsa.audio_render") == 0)
-+ return omxalsasink_create(pHandle, pAppData, pCallbacks);
-+
-+ return OMX_ErrorComponentNotFound;
-+}
-+
-+OMX_ERRORTYPE OMXALSA_FreeHandle(OMX_IN OMX_HANDLETYPE hComponent)
-+{
-+ return ((OMX_COMPONENTTYPE*)hComponent)->ComponentDeInit(hComponent);
-+}
-diff --git a/linux/OMXAlsa.h b/linux/OMXAlsa.h
-new file mode 100644
-index 0000000..b849288
---- /dev/null
-+++ b/linux/OMXAlsa.h
-@@ -0,0 +1,11 @@
-+#pragma once
-+#include <IL/OMX_Core.h>
-+
-+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMXALSA_GetHandle(
-+ OMX_OUT OMX_HANDLETYPE* pHandle,
-+ OMX_IN OMX_STRING cComponentName,
-+ OMX_IN OMX_PTR pAppData,
-+ OMX_IN OMX_CALLBACKTYPE* pCallBacks);
-+
-+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMXALSA_FreeHandle(
-+ OMX_IN OMX_HANDLETYPE hComponent);
-diff --git a/omxplayer.cpp b/omxplayer.cpp
-index 7e5dd03..7dddd31 100644
---- a/omxplayer.cpp
-+++ b/omxplayer.cpp
-@@ -578,6 +578,7 @@ int main(int argc, char *argv[])
- { "keys", no_argument, NULL, 'k' },
- { "aidx", required_argument, NULL, 'n' },
- { "adev", required_argument, NULL, 'o' },
-+ { "alsa", required_argument, NULL, 'A' },
- { "stats", no_argument, NULL, 's' },
- { "passthrough", no_argument, NULL, 'p' },
- { "vol", required_argument, NULL, vol_opt },
-@@ -646,7 +647,7 @@ int main(int argc, char *argv[])
- //Build default keymap just in case the --key-config option isn't used
- map<int,int> keymap = KeyConfig::buildDefaultKeymap();
-
-- while ((c = getopt_long(argc, argv, "wiIhvkn:l:o:cslb::pd3:Myzt:rg", longopts, NULL)) != -1)
-+ while ((c = getopt_long(argc, argv, "wiIhvkn:l:o:A:cslb::pd3:Myzt:rg", longopts, NULL)) != -1)
- {
- switch (c)
- {
-@@ -714,6 +715,9 @@ int main(int argc, char *argv[])
- }
- m_config_audio.device = "omx:" + m_config_audio.device;
- break;
-+ case 'A':
-+ m_config_audio.alsa_device = optarg;
-+ break;
- case 'i':
- m_dump_format = true;
- m_dump_format_exit = true;
---
-2.8.2
-
-
diff --git a/main/omxplayer/pull-req-465.patch b/main/omxplayer/pull-req-465.patch
deleted file mode 100644
index a9cd11836b..0000000000
--- a/main/omxplayer/pull-req-465.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-From 2cf933915ccd21ccecb791484ad91a9ee6089336 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
-Date: Mon, 16 May 2016 10:11:56 +0300
-Subject: [PATCH] Fix dbus message handling problems
-
-- make sure dbus messages are released after handling
-- return error to unknown method calls to avoid timeouts
----
- OMXControl.cpp | 24 ++++++++++++++++++++++++
- OMXControl.h | 2 ++
- 2 files changed, 26 insertions(+)
-
-diff --git a/OMXControl.cpp b/OMXControl.cpp
-index 834461f..7188834 100644
---- a/OMXControl.cpp
-+++ b/OMXControl.cpp
-@@ -158,7 +158,14 @@ OMXControlResult OMXControl::getEvent()
- return KeyConfig::ACTION_BLANK;
-
- CLog::Log(LOGDEBUG, "Popped message member: %s interface: %s type: %d path: %s", dbus_message_get_member(m), dbus_message_get_interface(m), dbus_message_get_type(m), dbus_message_get_path(m) );
-+ OMXControlResult result = handle_event(m);
-+ dbus_message_unref(m);
-
-+ return result;
-+}
-+
-+OMXControlResult OMXControl::handle_event(DBusMessage *m)
-+{
- if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_ROOT, "Quit"))
- {
- dbus_respond_ok(m);
-@@ -649,11 +656,28 @@ OMXControlResult OMXControl::getEvent()
- }
- else {
- CLog::Log(LOGWARNING, "Unhandled dbus message, member: %s interface: %s type: %d path: %s", dbus_message_get_member(m), dbus_message_get_interface(m), dbus_message_get_type(m), dbus_message_get_path(m) );
-+ if (dbus_message_get_type(m) == DBUS_MESSAGE_TYPE_METHOD_CALL)
-+ dbus_respond_error(m);
- }
-
- return KeyConfig::ACTION_BLANK;
- }
-
-+DBusHandlerResult OMXControl::dbus_respond_error(DBusMessage *m)
-+{
-+ DBusMessage *reply;
-+
-+ reply = dbus_message_new_error(m, DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
-+
-+ if (!reply)
-+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
-+
-+ dbus_connection_send(bus, reply, NULL);
-+ dbus_message_unref(reply);
-+
-+ return DBUS_HANDLER_RESULT_HANDLED;
-+}
-+
- DBusHandlerResult OMXControl::dbus_respond_ok(DBusMessage *m)
- {
- DBusMessage *reply;
-diff --git a/OMXControl.h b/OMXControl.h
-index b2786d5..b0c9a06 100644
---- a/OMXControl.h
-+++ b/OMXControl.h
-@@ -38,6 +38,8 @@ class OMXControl
- private:
- int dbus_connect(std::string& dbus_name);
- void dbus_disconnect();
-+ OMXControlResult handle_event(DBusMessage *m);
-+ DBusHandlerResult dbus_respond_error(DBusMessage *m);
- DBusHandlerResult dbus_respond_ok(DBusMessage *m);
- DBusHandlerResult dbus_respond_int64(DBusMessage *m, int64_t i);
- DBusHandlerResult dbus_respond_double(DBusMessage *m, double d);