Files
libstb-hal/raspi/omx_utils.c
Stefan Seyfried d71ae5b4f9 raspi/omx_utils: fix ordering of shutdown sequence
apparently, all ports need to be disabled before the inter-component
tunnels are teared down, otherwise video_decodeRIL:image pool objects
will leak
see http://www.raspberrypi.org/phpBB3/viewtopic.php?f=70&t=48177
2013-10-20 00:47:03 +02:00

1180 lines
43 KiB
C

/*
* this code is originally from
* pidvbip - tvheadend client for the Raspberry Pi
* (C) Dave Chapman 2012-2013
*
* adaption for libstb-hal
* (C) Stefan Seyfried 2013
*
* 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 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* omx_utils.c -- OMX helper functions for the Raspberry Pi
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "omx_utils.h"
#if 1
#define DEBUGF(...)
#else
#define DEBUGF(...) fprintf(stderr,__VA_ARGS__)
#endif
OMX_TICKS pts_to_omx(uint64_t pts)
{
OMX_TICKS ticks;
ticks.nLowPart = pts;
ticks.nHighPart = pts >> 32;
return ticks;
};
static int is_port_enabled(OMX_HANDLETYPE handle, int port)
{
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OMX_INIT_STRUCTURE(portdef);
portdef.nPortIndex = port;
OERR(OMX_GetParameter(handle, OMX_IndexParamPortDefinition, &portdef));
return (portdef.bEnabled == 0 ? 0 : 1);;
}
static void omx_show_state(struct omx_component_t* component, int port1, int port2, int port3)
{
OMX_STATETYPE state;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OERR(OMX_GetState(component->h, &state));
DEBUGF("%s is in state ",component->name);
switch (state) {
case OMX_StateInvalid: DEBUGF("OMX_StateInvalid\n"); break;
case OMX_StateLoaded: DEBUGF("OMX_StateLoaded\n"); break;
case OMX_StateIdle: DEBUGF("OMX_StateIdle\n"); break;
case OMX_StateExecuting: DEBUGF("OMX_StateExecuting\n"); break;
case OMX_StatePause: DEBUGF("OMX_StatePause\n"); break;
case OMX_StateWaitForResources: DEBUGF("OMX_StateWaitForResources\n"); break;
default:
DEBUGF("0x%08x\n",(unsigned int)state);
}
OMX_INIT_STRUCTURE(portdef);
if (port1) {
portdef.nPortIndex = port1;
OERR(OMX_GetParameter(component->h, OMX_IndexParamPortDefinition, &portdef));
DEBUGF("Port %d is %s\n",port1, (portdef.bEnabled == 0 ? "disabled" : "enabled"));
}
if (port2) {
portdef.nPortIndex = port2;
OERR(OMX_GetParameter(component->h, OMX_IndexParamPortDefinition, &portdef));
DEBUGF("Port %d is %s\n",port2, (portdef.bEnabled == 0 ? "disabled" : "enabled"));
}
if (port3) {
portdef.nPortIndex = port3;
OERR(OMX_GetParameter(component->h, OMX_IndexParamPortDefinition, &portdef));
DEBUGF("Port %d is %s\n",port3, (portdef.bEnabled == 0 ? "disabled" : "enabled"));
}
}
/* From omxtx */
/* Print some useful information about the state of the port: */
static void dumpport(OMX_HANDLETYPE handle, int port)
{
OMX_VIDEO_PORTDEFINITIONTYPE *viddef;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OMX_INIT_STRUCTURE(portdef);
portdef.nPortIndex = port;
OERR(OMX_GetParameter(handle, OMX_IndexParamPortDefinition, &portdef));
printf("Port %d is %s, %s\n", portdef.nPortIndex,
(portdef.eDir == 0 ? "input" : "output"),
(portdef.bEnabled == 0 ? "disabled" : "enabled"));
printf("Wants %d bufs, needs %d, size %d, enabled: %d, pop: %d, "
"aligned %d\n", portdef.nBufferCountActual,
portdef.nBufferCountMin, portdef.nBufferSize,
portdef.bEnabled, portdef.bPopulated,
portdef.nBufferAlignment);
viddef = &portdef.format.video;
switch (portdef.eDomain) {
case OMX_PortDomainVideo:
printf("Video type is currently:\n"
"\tMIME:\t\t%s\n"
"\tNative:\t\t%p\n"
"\tWidth:\t\t%d\n"
"\tHeight:\t\t%d\n"
"\tStride:\t\t%d\n"
"\tSliceHeight:\t%d\n"
"\tBitrate:\t%d\n"
"\tFramerate:\t%d (%x); (%f)\n"
"\tError hiding:\t%d\n"
"\tCodec:\t\t%d\n"
"\tColour:\t\t%d\n",
viddef->cMIMEType, viddef->pNativeRender,
viddef->nFrameWidth, viddef->nFrameHeight,
viddef->nStride, viddef->nSliceHeight,
viddef->nBitrate,
viddef->xFramerate, viddef->xFramerate,
((float)viddef->xFramerate/(float)65536),
viddef->bFlagErrorConcealment,
viddef->eCompressionFormat, viddef->eColorFormat);
break;
case OMX_PortDomainImage:
printf("Image type is currently:\n"
"\tMIME:\t\t%s\n"
"\tNative:\t\t%p\n"
"\tWidth:\t\t%d\n"
"\tHeight:\t\t%d\n"
"\tStride:\t\t%d\n"
"\tSliceHeight:\t%d\n"
"\tError hiding:\t%d\n"
"\tCodec:\t\t%d\n"
"\tColour:\t\t%d\n",
portdef.format.image.cMIMEType,
portdef.format.image.pNativeRender,
portdef.format.image.nFrameWidth,
portdef.format.image.nFrameHeight,
portdef.format.image.nStride,
portdef.format.image.nSliceHeight,
portdef.format.image.bFlagErrorConcealment,
portdef.format.image.eCompressionFormat,
portdef.format.image.eColorFormat);
break;
/* Feel free to add others. */
default:
break;
}
}
OMX_ERRORTYPE omx_send_command_and_wait0(struct omx_component_t* component, OMX_COMMANDTYPE Cmd, OMX_U32 nParam, OMX_PTR pCmdData)
{
pthread_mutex_lock(&component->cmd_queue_mutex);
component->cmd.hComponent = component->h;
component->cmd.Cmd = Cmd;
component->cmd.nParam = nParam;
component->cmd.pCmdData = pCmdData;
pthread_mutex_unlock(&component->cmd_queue_mutex);
OMX_SendCommand(component->h, Cmd, nParam, pCmdData);
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_send_command_and_wait1(struct omx_component_t* component, __attribute__((unused)) OMX_COMMANDTYPE Cmd, __attribute__((unused)) OMX_U32 nParam, __attribute__((unused)) OMX_PTR pCmdData)
{
pthread_mutex_lock(&component->cmd_queue_mutex);
while (component->cmd.hComponent) {
/* pthread_cond_wait releases the mutex (which must be locked) and blocks on the condition variable */
pthread_cond_wait(&component->cmd_queue_count_cv,&component->cmd_queue_mutex);
}
pthread_mutex_unlock(&component->cmd_queue_mutex);
//fprintf(stderr,"Command completed\n");
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_send_command_and_wait(struct omx_component_t* component, OMX_COMMANDTYPE Cmd, OMX_U32 nParam, OMX_PTR pCmdData)
{
omx_send_command_and_wait0(component,Cmd,nParam,pCmdData);
omx_send_command_and_wait1(component,Cmd,nParam,pCmdData);
return OMX_ErrorNone;
}
//void omx_wait_for_event(struct omx_pipeleine_t* pipe, OMX_HANDLETYPE *hComponent
// //&pipe,video_render, OMXEventBufferFlag, 90, OMX_BUFFERFLAG_EOS)
//{
//
//}
/* The event handler is called from the OMX component thread */
static OMX_ERRORTYPE omx_event_handler(OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_EVENTTYPE eEvent,
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData)
{
struct omx_component_t* component = (struct omx_component_t*)pAppData;
// fprintf(stderr,"[EVENT]: threadid=%u\n",(unsigned int)pthread_self());
switch (eEvent) {
case OMX_EventError:
fprintf(stderr,"[EVENT] %s %p has errored: %x\n", component->name, hComponent, (unsigned int)nData1);
//exit(1);
//fprintf(stderr,"[EVENT] Waiting for lock\n");
pthread_mutex_lock(&component->cmd_queue_mutex);
//fprintf(stderr,"[EVENT] Got lock - cmd.hComponent=%x\n",(unsigned int)pi->cmd.hComponent);
memset(&component->cmd,0,sizeof(component->cmd));
//fprintf(stderr,"[EVENT] Clearing cmd\n");
pthread_cond_signal(&component->cmd_queue_count_cv);
pthread_mutex_unlock(&component->cmd_queue_mutex);
//fprintf(stderr,"[EVENT] Returning from event\n");
return nData1;
break;
case OMX_EventCmdComplete:
DEBUGF("[EVENT] %s %p has completed the last command (%x).\n", component->name, hComponent, nData1);
//fprintf(stderr,"[EVENT] Waiting for lock\n");
pthread_mutex_lock(&component->cmd_queue_mutex);
//fprintf(stderr,"[EVENT] Got lock\n");
if ((nData1 == component->cmd.Cmd) &&
(nData2 == component->cmd.nParam)) {
memset(&component->cmd,0,sizeof(component->cmd));
pthread_cond_signal(&component->cmd_queue_count_cv);
}
pthread_mutex_unlock(&component->cmd_queue_mutex);
break;
case OMX_EventPortSettingsChanged:
DEBUGF("[EVENT] %s %p port %d settings changed.\n", component->name, hComponent, (unsigned int)nData1);
if (component->port_settings_changed == 0) { component->port_settings_changed = 1; }
break;
case OMX_EventBufferFlag:
DEBUGF("[EVENT] Got an EOS event on %s %p (port %d, d2 %x)\n", component->name, hComponent, (unsigned int)nData1, (unsigned int)nData2);
if (nData2 & OMX_BUFFERFLAG_EOS) {
pthread_mutex_lock(&component->eos_mutex);
component->eos = 1;
pthread_cond_signal(&component->eos_cv);
pthread_mutex_unlock(&component->eos_mutex);
DEBUGF("Sent cond signal for EOS event\n");
}
break;
case OMX_EventMark:
/* TODO: this cast is clearly wrong */
component->aspect = (int)((OMX_MARKTYPE*)pEventData);
//fprintf(stderr,"[EVENT] OMX_EventMark - component->aspect=%d\n",component->aspect);
break;
case OMX_EventParamOrConfigChanged:
DEBUGF("[EVENT] OMX_EventParamOrConfigChanged on component \"%s\" - d1=%x, d2=%x\n",component->name,(unsigned int)nData1, (unsigned int)nData2);
component->config_changed = 1;
break;
default:
DEBUGF("[EVENT] Got an event of type %x on %s %p (d1: %x, d2 %x)\n", eEvent,
component->name, hComponent, (unsigned int)nData1, (unsigned int)nData2);
}
return OMX_ErrorNone;
}
static OMX_ERRORTYPE omx_empty_buffer_done(__attribute__((unused)) OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_PTR pAppData,
__attribute__((unused)) OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
{
struct omx_component_t* component = (struct omx_component_t*)pAppData;
if (component->buf_notempty == 0) {
pthread_mutex_lock(&component->buf_mutex);
component->buf_notempty = 1;
pthread_cond_signal(&component->buf_notempty_cv);
pthread_mutex_unlock(&component->buf_mutex);
}
return OMX_ErrorNone;
}
void omx_clock_set_speed(struct omx_component_t *clk, int v)
{
OMX_TIME_CONFIG_SCALETYPE scale;
OMX_INIT_STRUCTURE(scale);
if (! clk->h) {
fprintf(stderr, "omx_clock_set_speed: clock->h is null!\n");
return;
}
scale.xScale = v;
OERR(OMX_SetConfig(clk->h, OMX_IndexConfigTimeScale, &scale));
}
static OMX_ERRORTYPE omx_fill_buffer_done(__attribute__((unused)) OMX_IN OMX_HANDLETYPE hComponent,
__attribute__((unused)) OMX_IN OMX_PTR pAppData,
__attribute__((unused)) OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
{
DEBUGF("[omx_fill_buffer_done]\n");
return OMX_ErrorNone;
}
/* Function based on ilclient_create_component() */
static void omx_disable_all_ports(struct omx_component_t* component)
{
OMX_PORT_PARAM_TYPE ports;
OMX_INDEXTYPE types[] = {OMX_IndexParamAudioInit, OMX_IndexParamVideoInit, OMX_IndexParamImageInit, OMX_IndexParamOtherInit};
int i;
ports.nSize = sizeof(OMX_PORT_PARAM_TYPE);
ports.nVersion.nVersion = OMX_VERSION;
for(i=0; i<4; i++) {
OMX_ERRORTYPE error = OMX_GetParameter(component->h, types[i], &ports);
if(error == OMX_ErrorNone) {
uint32_t j;
for(j=0; j<ports.nPorts; j++) {
//fprintf(stderr,"Disabling port %lu\n",ports.nStartPortNumber+j);
omx_send_command_and_wait(component, OMX_CommandPortDisable, ports.nStartPortNumber+j, NULL);
}
}
}
}
/* Based on allocbufs from omxtx.
Buffers are connected as a one-way linked list using pAppPrivate as the pointer to the next element */
void omx_alloc_buffers(struct omx_component_t *component, int port)
{
unsigned int i;
OMX_BUFFERHEADERTYPE *list = NULL, **end = &list;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OMX_INIT_STRUCTURE(portdef);
portdef.nPortIndex = port;
OERR(OMX_GetParameter(component->h, OMX_IndexParamPortDefinition, &portdef));
if (component == &component->pipe->audio_render) {
DEBUGF("Allocating %d buffers of %d bytes\n",(int)portdef.nBufferCountActual,(int)portdef.nBufferSize);
DEBUGF("portdef.bEnabled=%d\n",portdef.bEnabled);
}
for (i = 0; i < portdef.nBufferCountActual; i++) {
OMX_U8 *buf;
buf = vcos_malloc_aligned(portdef.nBufferSize, portdef.nBufferAlignment, "buffer");
// printf("Allocated a buffer of %u bytes\n",(unsigned int)portdef.nBufferSize);
OERR(OMX_UseBuffer(component->h, end, port, NULL, portdef.nBufferSize, buf));
end = (OMX_BUFFERHEADERTYPE **) &((*end)->pAppPrivate);
}
component->buffers = list;
}
void omx_free_buffers(struct omx_component_t *component, int port)
{
OMX_BUFFERHEADERTYPE *buf, *prev;
// int i=0;
buf = component->buffers;
while (buf) {
prev = buf->pAppPrivate;
OERR(OMX_FreeBuffer(component->h, port, buf)); /* This also calls free() */
buf = prev;
}
}
int omx_get_free_buffer_count(struct omx_component_t* component)
{
int n = 0;
OMX_BUFFERHEADERTYPE *buf = component->buffers;
pthread_mutex_lock(&component->buf_mutex);
while (buf) {
if (buf->nFilledLen == 0) n++;
buf = buf->pAppPrivate;
}
pthread_mutex_unlock(&component->buf_mutex);
return n;
}
#if 0
static void dump_buffer_status(OMX_BUFFERHEADERTYPE *buffers)
{
OMX_BUFFERHEADERTYPE *buf = buffers;
while (buf) {
fprintf(stderr,"*****\n");
fprintf(stderr,"buf->pAppPrivate=%u\n",(unsigned int)buf->pAppPrivate);
fprintf(stderr,"buf->nAllocLen=%u\n",(unsigned int)buf->nAllocLen);
fprintf(stderr,"buf->nFilledLen=%u\n",(unsigned int)buf->nFilledLen);
fprintf(stderr,"buf->pBuffer=%u\n",(unsigned int)buf->pBuffer);
fprintf(stderr,"buf->nOffset=%u\n",(unsigned int)buf->nOffset);
fprintf(stderr,"buf->nFlags=%u\n",(unsigned int)buf->nFlags);
fprintf(stderr,"buf->nInputPortIndex=%u\n",(unsigned int)buf->nInputPortIndex);
fprintf(stderr,"buf->nOutputPortIndex=%u\n",(unsigned int)buf->nOutputPortIndex);
buf = buf->pAppPrivate;
}
}
#endif
void summarise_buffers(OMX_BUFFERHEADERTYPE *buffers)
{
OMX_BUFFERHEADERTYPE *buf = buffers;
fprintf(stderr,"*******\n");
while (buf) {
fprintf(stderr,"buf->nFilledLen=%u\n",(unsigned int)buf->nFilledLen);
buf = buf->pAppPrivate;
}
}
/* Return the next free buffer, or NULL if none are free */
OMX_BUFFERHEADERTYPE *get_next_buffer(struct omx_component_t* component)
{
OMX_BUFFERHEADERTYPE *ret;
retry:
pthread_mutex_lock(&component->buf_mutex);
ret = component->buffers;
while (ret && ret->nFilledLen > 0)
ret = ret->pAppPrivate;
if (!ret)
component->buf_notempty = 0;
if (ret) {
pthread_mutex_unlock(&component->buf_mutex);
return ret;
}
//summarise_buffers(pi->video_buffers);
while (component->buf_notempty == 0)
pthread_cond_wait(&component->buf_notempty_cv,&component->buf_mutex);
pthread_mutex_unlock(&component->buf_mutex);
goto retry;
/* We never get here, but keep GCC happy */
return NULL;
}
OMX_ERRORTYPE omx_flush_tunnel(struct omx_component_t* source, int source_port, struct omx_component_t* sink, int sink_port)
{
omx_send_command_and_wait(source,OMX_CommandFlush,source_port,NULL);
omx_send_command_and_wait(sink,OMX_CommandFlush,sink_port,NULL);
return OMX_ErrorNone;
}
static void omx_config_pcm(struct omx_component_t* audio_render, int samplerate, int channels, int bitdepth, char* dest)
{
OMX_AUDIO_PARAM_PCMMODETYPE pcm;
// int32_t s;
OMX_INIT_STRUCTURE(pcm);
pcm.nPortIndex = 100;
pcm.nChannels = channels;
pcm.eNumData = OMX_NumericalDataSigned;
pcm.eEndian = OMX_EndianLittle;
pcm.nSamplingRate = samplerate;
pcm.bInterleaved = OMX_TRUE;
pcm.nBitPerSample = bitdepth;
pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
switch(channels) {
case 1:
pcm.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
break;
case 8:
pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
pcm.eChannelMapping[2] = OMX_AUDIO_ChannelCF;
pcm.eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
pcm.eChannelMapping[4] = OMX_AUDIO_ChannelLR;
pcm.eChannelMapping[5] = OMX_AUDIO_ChannelRR;
pcm.eChannelMapping[6] = OMX_AUDIO_ChannelLS;
pcm.eChannelMapping[7] = OMX_AUDIO_ChannelRS;
break;
case 4:
pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
pcm.eChannelMapping[2] = OMX_AUDIO_ChannelLR;
pcm.eChannelMapping[3] = OMX_AUDIO_ChannelRR;
break;
case 2:
pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
break;
}
OERR(OMX_SetParameter(audio_render->h, OMX_IndexParamAudioPcm, &pcm));
OMX_CONFIG_BRCMAUDIODESTINATIONTYPE ar_dest;
OMX_INIT_STRUCTURE(ar_dest);
strcpy((char *)ar_dest.sName, dest);
OERR(OMX_SetConfig(audio_render->h, OMX_IndexConfigBrcmAudioDestination, &ar_dest));
}
void omx_audio_volume(struct omx_component_t* audio_render, long vol)
{
OMX_AUDIO_CONFIG_VOLUMETYPE volume;
OMX_INIT_STRUCTURE(volume);
volume.nPortIndex = 100;
volume.sVolume.nValue = vol;
OMX_ERRORTYPE omx_err = OMX_SetParameter(audio_render->h, OMX_IndexConfigAudioVolume, &volume);
if (omx_err != OMX_ErrorNone)
printf("[acodec] omx_audio_volume failed 0x%x\n", omx_err);
}
void omx_set_display_region(struct omx_pipeline_t* pi, int x, int y, int width, int height)
{
OMX_CONFIG_DISPLAYREGIONTYPE region;
OMX_INIT_STRUCTURE(region);
region.nPortIndex = 90; /* Video render input port */
region.set = OMX_DISPLAY_SET_DEST_RECT | OMX_DISPLAY_SET_FULLSCREEN | OMX_DISPLAY_SET_NOASPECT;
region.fullscreen = OMX_FALSE;
region.noaspect = OMX_TRUE;
region.dest_rect.x_offset = x;
region.dest_rect.y_offset = y;
region.dest_rect.width = width;
region.dest_rect.height = height;
DEBUGF("Setting display region\n");
OERR(OMX_SetParameter(pi->video_render.h, OMX_IndexConfigDisplayRegion, &region));
}
OMX_ERRORTYPE omx_init_component(struct omx_pipeline_t* pi, struct omx_component_t* component, char* compname)
{
memset(component,0,sizeof(struct omx_component_t));
pthread_mutex_init(&component->cmd_queue_mutex, NULL);
pthread_cond_init(&component->cmd_queue_count_cv,NULL);
component->buf_notempty = 1;
pthread_cond_init(&component->buf_notempty_cv,NULL);
pthread_cond_init(&component->eos_cv,NULL);
pthread_mutex_init(&component->eos_mutex,NULL);
component->callbacks.EventHandler = omx_event_handler;
component->callbacks.EmptyBufferDone = omx_empty_buffer_done;
component->callbacks.FillBufferDone = omx_fill_buffer_done;
component->pipe = pi;
component->name = compname;
/* Create OMX component */
OERR(OMX_GetHandle(&component->h, compname, component, &component->callbacks));
/* Disable all ports */
omx_disable_all_ports(component);
return OMX_ErrorNone;
}
/* From: http://home.nouwen.name/RaspberryPi/documentation/ilcomponents/camera.html
In order to optimise loading of relevant drivers, the recommended initialisation sequence is:
Create component.
Use OMX_IndexConfigRequestCallback to request callbacks on OMX_IndexParamCameraDeviceNumber.
Set OMX_IndexParamISPTunerName.
Set OMX_IndexParamCameraFlashType.
Set OMX_IndexParamCameraDeviceNumber.
Wait for the callback that OMX_IndexParamCameraDeviceNumber has changed. At this point, all the drivers have been loaded. Other settings can be applied whilst waiting for this event.
Query for OMX_IndexConfigCameraSensorModes as required.
Change state to IDLE, and proceed as required.
*/
OMX_ERRORTYPE omx_setup_camera_pipeline(struct omx_pipeline_t* pi)
{
// Create component.
omx_init_component(pi, &pi->camera, "OMX.broadcom.camera");
// Use OMX_IndexConfigRequestCallback to request callbacks on OMX_IndexParamCameraDeviceNumber.
OMX_CONFIG_REQUESTCALLBACKTYPE cbtype;
OMX_INIT_STRUCTURE(cbtype);
cbtype.nPortIndex=OMX_ALL;
cbtype.nIndex=OMX_IndexParamCameraDeviceNumber;
cbtype.bEnable = OMX_TRUE;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigRequestCallback, &cbtype));
// Set OMX_IndexParamISPTunerName.
// Set OMX_IndexParamCameraFlashType.
// Set OMX_IndexParamCameraDeviceNumber.
OMX_PARAM_U32TYPE device;
OMX_INIT_STRUCTURE(device);
device.nPortIndex = OMX_ALL;
device.nU32 = 0;
OERR(OMX_SetParameter(pi->camera.h, OMX_IndexParamCameraDeviceNumber, &device));
dumpport(pi->camera.h, 71);
/* Set the resolution */
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OMX_INIT_STRUCTURE(portdef);
portdef.nPortIndex = 71;
OERR(OMX_GetParameter(pi->camera.h, OMX_IndexParamPortDefinition, &portdef));
portdef.format.image.nFrameWidth = 640;
portdef.format.image.nFrameHeight = 360;
portdef.format.image.nStride = 640;
OERR(OMX_SetParameter(pi->camera.h, OMX_IndexParamPortDefinition, &portdef));
/* Set the framerate */
OMX_CONFIG_FRAMERATETYPE framerate;
OMX_INIT_STRUCTURE(framerate);
framerate.nPortIndex = 71;
framerate.xEncodeFramerate = 25 << 16; // Q16 format - 25fps
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigVideoFramerate, &framerate));
/* Set the sharpness */
OMX_CONFIG_SHARPNESSTYPE sharpness;
OMX_INIT_STRUCTURE(sharpness);
sharpness.nPortIndex = OMX_ALL;
sharpness.nSharpness = -50; /* -100 to 100 */
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonSharpness, &sharpness));
/* Set the contrast */
OMX_CONFIG_CONTRASTTYPE contrast;
OMX_INIT_STRUCTURE(contrast);
contrast.nPortIndex = OMX_ALL;
contrast.nContrast = -10; /* -100 to 100 */
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonContrast, &contrast));
/* Set the brightness */
OMX_CONFIG_BRIGHTNESSTYPE brightness;
OMX_INIT_STRUCTURE(brightness);
brightness.nPortIndex = OMX_ALL;
brightness.nBrightness = 50; /* 0 to 100 */
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonBrightness, &brightness));
/* Set the saturation */
OMX_CONFIG_SATURATIONTYPE saturation;
OMX_INIT_STRUCTURE(saturation);
saturation.nPortIndex = OMX_ALL;
saturation.nSaturation = 0; /* -100 to 100 */
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonSaturation, &saturation));
/* Video stabilisation */
OMX_CONFIG_FRAMESTABTYPE framestab;
OMX_INIT_STRUCTURE(framestab);
framestab.nPortIndex = OMX_ALL;
framestab.bStab = OMX_FALSE;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonFrameStabilisation, &framestab));
/* Set EV compensation, ISO and metering mode */
OMX_CONFIG_EXPOSUREVALUETYPE exposurevalue;
OMX_INIT_STRUCTURE(exposurevalue);
exposurevalue.nPortIndex = OMX_ALL;
OERR(OMX_GetConfig(pi->camera.h, OMX_IndexConfigCommonExposureValue, &exposurevalue));
fprintf(stderr,"nSensitivity=%d\n",exposurevalue.nSensitivity);
exposurevalue.xEVCompensation = 0; /* Fixed point value stored as Q16 */
exposurevalue.nSensitivity = 100; /**< e.g. nSensitivity = 100 implies "ISO 100" */
exposurevalue.bAutoSensitivity = OMX_FALSE;
exposurevalue.eMetering = OMX_MeteringModeAverage;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonExposureValue, &exposurevalue));
/* Set exposure mode */
OMX_CONFIG_EXPOSURECONTROLTYPE exposure;
OMX_INIT_STRUCTURE(exposure);
exposure.nPortIndex = OMX_ALL;
exposure.eExposureControl = OMX_ExposureControlAuto;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonExposure, &exposure));
/* Set AWB mode */
OMX_CONFIG_WHITEBALCONTROLTYPE awb;
OMX_INIT_STRUCTURE(awb);
awb.nPortIndex = OMX_ALL;
awb.eWhiteBalControl = OMX_WhiteBalControlAuto;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonWhiteBalance, &awb));
/* Set image effect */
OMX_CONFIG_IMAGEFILTERTYPE imagefilter;
OMX_INIT_STRUCTURE(imagefilter);
imagefilter.nPortIndex = OMX_ALL;
imagefilter.eImageFilter = OMX_ImageFilterNone;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonImageFilter, &imagefilter));
/* Set colour effect */
OMX_CONFIG_COLORENHANCEMENTTYPE colour;
OMX_INIT_STRUCTURE(colour);
colour.nPortIndex = OMX_ALL;
colour.bColorEnhancement = OMX_FALSE;
colour.nCustomizedU = 128;
colour.nCustomizedV = 128;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigCommonColorEnhancement, &colour));
/* Turn off the LED - doesn't work! */
OMX_CONFIG_PRIVACYINDICATORTYPE privacy;
OMX_INIT_STRUCTURE(privacy);
privacy.ePrivacyIndicatorMode = OMX_PrivacyIndicatorOff;
OERR(OMX_SetConfig(pi->camera.h, OMX_IndexConfigPrivacyIndicator, &privacy));
// Wait for the callback that OMX_IndexParamCameraDeviceNumber has
// changed. At this point, all the drivers have been loaded. Other
// settings can be applied whilst waiting for this event.
fprintf(stderr,"Waiting for camera config to change\n");
while (!pi->camera.config_changed); /* TODO: Use a condition variable */
fprintf(stderr,"Config changed\n");
// Query for OMX_IndexConfigCameraSensorModes as required.
// Change state to IDLE, and proceed as required.
omx_send_command_and_wait(&pi->camera, OMX_CommandStateSet, OMX_StateIdle, NULL);
OMX_CONFIG_PORTBOOLEANTYPE cameraport;
OMX_INIT_STRUCTURE(cameraport);
cameraport.nPortIndex = 71;
cameraport.bEnabled = OMX_TRUE;
OERR(OMX_SetParameter(pi->camera.h, OMX_IndexConfigPortCapturing, &cameraport));
omx_init_component(pi, &pi->video_render, "OMX.broadcom.video_render");
omx_send_command_and_wait(&pi->video_render, OMX_CommandStateSet, OMX_StateIdle, NULL);
OERR(OMX_SetupTunnel(pi->camera.h, 71, pi->video_render.h, 90)); /* Camera capture port to video render */
omx_send_command_and_wait(&pi->camera, OMX_CommandPortEnable, 71, NULL);
omx_send_command_and_wait(&pi->video_render, OMX_CommandPortEnable, 90, NULL);
omx_send_command_and_wait(&pi->video_render, OMX_CommandStateSet, OMX_StateExecuting, NULL);
omx_send_command_and_wait(&pi->camera, OMX_CommandStateSet, OMX_StateExecuting, NULL);
omx_set_display_region(pi, 1200, 180, 640, 360);
OMX_CONFIG_DISPLAYREGIONTYPE region;
OMX_INIT_STRUCTURE(region);
region.nPortIndex = 90; /* Video render input port */
region.set = OMX_DISPLAY_SET_LAYER;
region.layer = 10;
OERR(OMX_SetParameter(pi->video_render.h, OMX_IndexConfigDisplayRegion, &region));
fprintf(stderr,"Camera pipeline configured\n");
dumpport(pi->camera.h, 71);
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_setup_pipeline(struct omx_pipeline_t* pi, OMX_VIDEO_CODINGTYPE video_codec, char* audio_dest, __attribute__((unused)) int is_hd)
{
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
OMX_CONFIG_BOOLEANTYPE configBoolTrue;
OMX_INIT_STRUCTURE(configBoolTrue);
configBoolTrue.bEnabled = OMX_TRUE;
pi->do_deinterlace = 0;
#if 0
if (((is_hd == 0) && (global_settings.deinterlace_sd)) || ((is_hd == 1) && (global_settings.deinterlace_hd))) {
DEBUGF("Enabling de-interlace\n");
pi->do_deinterlace = 1;
}
#endif
omx_init_component(pi, &pi->video_decode, "OMX.broadcom.video_decode");
omx_init_component(pi, &pi->video_render, "OMX.broadcom.video_render");
if (pi->do_deinterlace) {
DEBUGF("Enabling de-interlacer\n");
/* De-interlacer. Input port 190, Output port 191. Insert between decoder and scheduler */
omx_init_component(pi, &pi->image_fx, "OMX.broadcom.image_fx");
/* Configure image_fx */
omx_send_command_and_wait(&pi->image_fx, OMX_CommandStateSet, OMX_StateIdle, NULL);
OMX_CONFIG_IMAGEFILTERPARAMSTYPE imagefilter;
OMX_INIT_STRUCTURE(imagefilter);
imagefilter.nPortIndex=191;
imagefilter.nNumParams=1;
imagefilter.nParams[0]=3; //???
imagefilter.eImageFilter=OMX_ImageFilterDeInterlaceAdvanced;
OERR(OMX_SetConfig(pi->image_fx.h, OMX_IndexConfigCommonImageFilterParameters, &imagefilter));
} else {
memset(&pi->image_fx,0,sizeof(struct omx_component_t));
}
omx_init_component(pi, &pi->clock, "OMX.broadcom.clock");
OMX_INIT_STRUCTURE(cstate);
cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
cstate.nWaitMask = OMX_CLOCKPORT0|OMX_CLOCKPORT1;
OERR(OMX_SetParameter(pi->clock.h, OMX_IndexConfigTimeClockState, &cstate));
OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock;
OMX_INIT_STRUCTURE(refClock);
refClock.eClock = OMX_TIME_RefClockAudio;
OERR(OMX_SetConfig(pi->clock.h, OMX_IndexConfigTimeActiveRefClock, &refClock));
omx_init_component(pi, &pi->video_scheduler, "OMX.broadcom.video_scheduler");
/* Initialise audio output - hardcoded to 48000/Stereo/16-bit */
omx_init_component(pi, &pi->audio_render, "OMX.broadcom.audio_render");
OMX_PARAM_PORTDEFINITIONTYPE param;
OMX_INIT_STRUCTURE(param);
param.nPortIndex = 100;
OERR(OMX_GetParameter(pi->audio_render.h, OMX_IndexParamPortDefinition, &param));
param.nBufferSize = 8192; /* Needs to be big enough for one frame of data */
param.nBufferCountActual = 32; /* Arbitrary */
OERR(OMX_SetParameter(pi->audio_render.h, OMX_IndexParamPortDefinition, &param));
omx_config_pcm(&pi->audio_render, 48000, 2, 16, audio_dest);
OERR(OMX_SetConfig(pi->audio_render.h, OMX_IndexConfigBrcmClockReferenceSource, &configBoolTrue));
omx_send_command_and_wait(&pi->audio_render, OMX_CommandStateSet, OMX_StateIdle, NULL);
omx_send_command_and_wait0(&pi->audio_render, OMX_CommandPortEnable, 100, NULL);
omx_alloc_buffers(&pi->audio_render, 100);
omx_send_command_and_wait1(&pi->audio_render, OMX_CommandPortEnable, 100, NULL);
/* Setup clock tunnels first */
omx_send_command_and_wait(&pi->clock, OMX_CommandStateSet, OMX_StateIdle, NULL);
OERR(OMX_SetupTunnel(pi->clock.h, 80, pi->audio_render.h, 101));
OERR(OMX_SetupTunnel(pi->clock.h, 81, pi->video_scheduler.h, 12));
OERR(OMX_SendCommand(pi->clock.h, OMX_CommandPortEnable, 80, NULL));
OERR(OMX_SendCommand(pi->video_scheduler.h, OMX_CommandPortEnable, 12, NULL));
OERR(OMX_SendCommand(pi->clock.h, OMX_CommandPortEnable, 81, NULL));
OERR(OMX_SendCommand(pi->audio_render.h, OMX_CommandPortEnable, 101, NULL));
omx_send_command_and_wait(&pi->video_scheduler, OMX_CommandStateSet, OMX_StateIdle, NULL);
omx_send_command_and_wait(&pi->clock, OMX_CommandStateSet, OMX_StateExecuting, NULL);
/* Configure video_decoder */
omx_send_command_and_wait(&pi->video_decode, OMX_CommandStateSet, OMX_StateIdle, NULL);
/* Enable lazy image pool destroying */
OERR(OMX_SetConfig(pi->video_decode.h, OMX_IndexParamBrcmLazyImagePoolDestroy, &configBoolTrue));
OMX_INIT_STRUCTURE(format);
format.nPortIndex = 130;
format.eCompressionFormat = video_codec;
OERR(OMX_SetParameter(pi->video_decode.h, OMX_IndexParamVideoPortFormat, &format));
/* Enable error concealment for H264 only - without this, HD channels don't work reliably */
if (video_codec == OMX_VIDEO_CodingAVC) {
OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE ec;
OMX_INIT_STRUCTURE(ec);
ec.bStartWithValidFrame = OMX_FALSE;
OERR(OMX_SetParameter(pi->video_decode.h, OMX_IndexParamBrcmVideoDecodeErrorConcealment, &ec));
}
/* Enable video decoder input port */
omx_send_command_and_wait0(&pi->video_decode, OMX_CommandPortEnable, 130, NULL);
/* Allocate input buffers */
omx_alloc_buffers(&pi->video_decode, 130);
/* Wait for input port to be enabled */
omx_send_command_and_wait1(&pi->video_decode, OMX_CommandPortEnable, 130, NULL);
/* Change video_decode to OMX_StateExecuting */
omx_send_command_and_wait(&pi->video_decode, OMX_CommandStateSet, OMX_StateExecuting, NULL);
/* Change audio_render to OMX_StateExecuting */
omx_send_command_and_wait(&pi->audio_render, OMX_CommandStateSet, OMX_StateExecuting, NULL);
/* Enable passing of buffer marks */
OERR(OMX_SetParameter(pi->video_decode.h, OMX_IndexParamPassBufferMarks, &configBoolTrue));
OERR(OMX_SetParameter(pi->video_render.h, OMX_IndexParamPassBufferMarks, &configBoolTrue));
return OMX_ErrorNone;
}
void omx_teardown_pipeline(struct omx_pipeline_t* pi)
{
// OMX_BUFFERHEADERTYPE *buf;
// int i=1;
DEBUGF("[vcodec] omx_teardown pipeline:\n");
DEBUGF("pipe->video_decode.port_settings_changed = %d\n",pi->video_decode.port_settings_changed);
DEBUGF("pipe->image_fx.port_settings_changed = %d\n",pi->image_fx.port_settings_changed);
DEBUGF("pipe->video_scheduler.port_settings_changed = %d\n",pi->video_scheduler.port_settings_changed);
//dumpport(pi->video_decode.h,130);
#if 0
/* Indicate end of video stream */
buf = get_next_buffer(&pi->video_decode);
buf->nFilledLen = 0;
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
OERR(OMX_EmptyThisBuffer(pi->video_decode.h, buf));
/* NOTE: Three events are sent after the previous command:
[EVENT] Got an event of type 4 on video_decode 0x426a10 (d1: 83, d2 1)
[EVENT] Got an event of type 4 on video_scheduler 0x430d10 (d1: b, d2 1)
[EVENT] Got an event of type 4 on video_render 0x430b30 (d1: 5a, d2 1) 5a = port (90) 1 = OMX_BUFFERFLAG_EOS
*/
#endif
#if 0
DEBUGF("[vcodec] omx_teardown pipeline 2\n");
/* Wait for video_decode to shutdown */
pthread_mutex_lock(&pi->video_decode.eos_mutex);
while (!pi->video_decode.eos)
pthread_cond_wait(&pi->video_decode.eos_cv,&pi->video_decode.eos_mutex);
pthread_mutex_unlock(&pi->video_decode.eos_mutex);
#endif
DEBUGF("[vcodec] omx_teardown pipeline 1\n");
/* Transition all components to Idle, if they have been initialised */
omx_send_command_and_wait(&pi->video_decode, OMX_CommandStateSet, OMX_StateIdle, NULL);
omx_send_command_and_wait(&pi->clock, OMX_CommandStateSet, OMX_StateIdle, NULL);
DEBUGF("pipe->do_deinterlace=%d, pipe->image_fx=%d\n",pi->do_deinterlace,(int)pi->image_fx.h);
if (pi->video_decode.port_settings_changed == 2) {
if (pi->do_deinterlace) {
omx_send_command_and_wait(&pi->image_fx, OMX_CommandStateSet, OMX_StateIdle, NULL);
} else {
omx_send_command_and_wait(&pi->video_scheduler, OMX_CommandStateSet, OMX_StateIdle, NULL);
}
}
if (pi->image_fx.port_settings_changed == 2) {
omx_send_command_and_wait(&pi->video_scheduler, OMX_CommandStateSet, OMX_StateIdle, NULL);
}
if (pi->video_scheduler.port_settings_changed == 2) {
omx_send_command_and_wait(&pi->video_render, OMX_CommandStateSet, OMX_StateIdle, NULL);
}
omx_send_command_and_wait(&pi->audio_render, OMX_CommandStateSet, OMX_StateIdle, NULL);
#if 0
DEBUGF("[vcodec] omx_teardown pipeline 2\n");
/* Wait for video_render to shutdown */
pthread_mutex_lock(&pi->video_render.eos_mutex);
while (!pi->video_render.eos)
pthread_cond_wait(&pi->video_render.eos_cv,&pi->video_render.eos_mutex);
pthread_mutex_unlock(&pi->video_render.eos_mutex);
#endif
/*
Pipeline is as follows:
[video data] -> 130 video_decode 131 -> 190 image_fx 191 -> 10 video_scheduler 11 -> 90 video_render
clock 81 -> 12 video_scheduler
clock 80 -> 101 audio_render
[audio data] -> 100 audio_render
*/
/* Flush entrances to pipeline */
omx_send_command_and_wait(&pi->video_decode,OMX_CommandFlush,130,NULL);
omx_send_command_and_wait(&pi->audio_render,OMX_CommandFlush,100,NULL);
/* Flush all tunnels */
DEBUGF("[vcodec] omx_teardown pipeline 3\n");
if (pi->do_deinterlace) {
omx_flush_tunnel(&pi->video_decode, 131, &pi->image_fx, 190);
omx_flush_tunnel(&pi->image_fx, 191, &pi->video_scheduler, 10);
} else {
omx_flush_tunnel(&pi->video_decode, 131, &pi->video_scheduler, 10);
}
DEBUGF("[vcodec] omx_teardown pipeline 4\n");
omx_flush_tunnel(&pi->video_scheduler, 11, &pi->video_render, 90);
omx_flush_tunnel(&pi->clock, 81, &pi->video_scheduler, 12);
DEBUGF("[vcodec] omx_teardown pipeline 2b\n");
omx_send_command_and_wait(&pi->video_scheduler,OMX_CommandFlush,10,NULL);
DEBUGF("[vcodec] omx_teardown pipeline 5\n");
omx_flush_tunnel(&pi->clock, 80, &pi->audio_render, 101);
/* Disable audio_render input port and buffers */
omx_send_command_and_wait0(&pi->audio_render, OMX_CommandPortDisable, 100, NULL);
omx_free_buffers(&pi->audio_render, 100);
omx_send_command_and_wait1(&pi->audio_render, OMX_CommandPortDisable, 100, NULL);
DEBUGF("[vcodec] omx_teardown pipeline 9\n");
/* Scheduler -> render tunnel */
if (pi->video_scheduler.port_settings_changed == 2) {
omx_send_command_and_wait(&pi->video_scheduler, OMX_CommandPortDisable, 11, NULL);
omx_send_command_and_wait(&pi->video_render, OMX_CommandPortDisable, 90, NULL);
omx_send_command_and_wait(&pi->video_scheduler, OMX_CommandPortDisable, 10, NULL);
}
if ((pi->image_fx.port_settings_changed == 2) && (pi->do_deinterlace)) {
omx_send_command_and_wait(&pi->image_fx, OMX_CommandPortDisable, 190, NULL);
omx_send_command_and_wait(&pi->image_fx, OMX_CommandPortDisable, 191, NULL);
}
DEBUGF("[vcodec] omx_teardown pipeline 10\n");
/* NOTE: The clock disable doesn't complete until after the video scheduler port is
disabled (but it completes before the video scheduler port disabling completes). */
OERR(OMX_SendCommand(pi->clock.h, OMX_CommandPortDisable, 80, NULL));
omx_send_command_and_wait(&pi->audio_render, OMX_CommandPortDisable, 101, NULL);
OERR(OMX_SendCommand(pi->clock.h, OMX_CommandPortDisable, 81, NULL));
omx_send_command_and_wait(&pi->video_scheduler, OMX_CommandPortDisable, 12, NULL);
if (pi->video_decode.port_settings_changed == 2) {
//dumpport(pi->video_decode.h,131);
omx_send_command_and_wait(&pi->video_decode, OMX_CommandPortDisable, 131, NULL);
}
DEBUGF("[vcodec] omx_teardown pipeline 11\n");
/* Disable video_decode input port and buffers */
//dumpport(pi->video_decode.h,130);
omx_send_command_and_wait0(&pi->video_decode, OMX_CommandPortDisable, 130, NULL);
DEBUGF("[vcodec] omx_teardown pipeline 6\n");
omx_free_buffers(&pi->video_decode, 130);
DEBUGF("[vcodec] omx_teardown pipeline 7\n");
omx_send_command_and_wait1(&pi->video_decode, OMX_CommandPortDisable, 130, NULL);
DEBUGF("[vcodec] omx_teardown pipeline 8a\n");
//dumpport(pi->video_scheduler.h,10);
#if 0
/* ports need to be disabled before tunnels are shut down. Otherwise,
* "video_decodeRIL:image pool" buffers will leak (check with "vcdbg reloc"
* the following paranoia checks are not necessary, because
* omx_send_command_and_wait() waits for completion
*/
fprintf(stderr,"is_enabled 130\n");
while (is_port_enabled(pi->video_decode.h, 130))
{fprintf(stderr, "."); usleep(1);}
fprintf(stderr,"is_enabled 131\n");
while (is_port_enabled(pi->video_decode.h, 131))
{fprintf(stderr, "."); usleep(1);}
fprintf(stderr,"is_enabled 10\n");
while (is_port_enabled(pi->video_scheduler.h, 10))
{fprintf(stderr, "."); usleep(1);}
fprintf(stderr,"is_enabled 11\n");
while (is_port_enabled(pi->video_scheduler.h, 11))
{fprintf(stderr, "."); usleep(1);}
fprintf(stderr,"is_enabled 90\n");
while (is_port_enabled(pi->video_render.h, 90))
{fprintf(stderr, "."); usleep(1);}
fprintf(stderr,"is_enabled 101\n");
while (is_port_enabled(pi->audio_render.h, 101))
{fprintf(stderr, "."); usleep(1);}
fprintf(stderr,"is_enabled 100\n");
while (is_port_enabled(pi->audio_render.h, 100))
{fprintf(stderr, "."); usleep(1);}
DEBUGF("[vcodec] omx_teardown pipeline 8b\n");
#endif
omx_show_state(&pi->video_decode,130,131,0);
dumpport(pi->video_decode.h,131);
omx_show_state(&pi->video_scheduler,10,11,12);
if (pi->do_deinterlace) { omx_show_state(&pi->image_fx,190,191,0); }
omx_show_state(&pi->video_render,90,0,0);
omx_show_state(&pi->audio_render,100,101,0);
omx_show_state(&pi->clock,80,81,0);
DEBUGF("[vcodec] omx_teardown pipeline 8c\n");
/* Teardown tunnels */
/*
Pipeline is as follows:
[video data] -> 130 video_decode 131 -> 190 image_fx 191 -> 10 video_scheduler 11 -> 90 video_render
clock 81 -> 12 video_scheduler
clock 80 -> 101 audio_render
[audio data] -> 100 audio_render
*/
//dumpport(pi->video_decode.h,131);
OERR(OMX_SetupTunnel(pi->video_scheduler.h, 10, NULL, 0));
DEBUGF("[vcodec] omx_teardown pipeline 12b\n");
if (pi->do_deinterlace) {
OERR(OMX_SetupTunnel(pi->image_fx.h, 190, NULL, 0));
OERR(OMX_SetupTunnel(pi->image_fx.h, 191, NULL, 0));
}
DEBUGF("[vcodec] omx_teardown pipeline 13\n");
OERR(OMX_SetupTunnel(pi->video_scheduler.h, 11, NULL, 0));
OERR(OMX_SetupTunnel(pi->video_render.h, 90, NULL, 0));
OERR(OMX_SetupTunnel(pi->clock.h, 81, NULL, 0));
OERR(OMX_SetupTunnel(pi->video_scheduler.h, 12, NULL, 0));
DEBUGF("[vcodec] omx_teardown pipeline 13b\n");
OERR(OMX_SetupTunnel(pi->clock.h, 80, NULL, 0));
OERR(OMX_SetupTunnel(pi->audio_render.h, 101, NULL, 0));
DEBUGF("[vcodec] omx_teardown pipeline 8b\n");
/*
Pipeline is as follows:
[video data] -> 130 video_decode 131 -> 190 image_fx 191 -> 10 video_scheduler 11 -> 90 video_render
clock 81 -> 12 video_scheduler
clock 80 -> 101 audio_render
[audio data] -> 100 audio_render
*/
//dumpport(pi->video_decode.h,130);
if (is_port_enabled(pi->video_decode.h, 130)) {
fprintf(stderr,"Unexpected error video_decode port 130 is not disabled\n");
exit(1);
}
DEBUGF("[vcodec] omx_teardown pipeline 12\n");
OERR(OMX_SetupTunnel(pi->video_decode.h, 131, NULL, 0));
DEBUGF("[vcodec] omx_teardown pipeline 15\n");
omx_show_state(&pi->video_decode,130,131,0);
/* Transition all components to Loaded */
DEBUGF("[vcodec] omx_teardown pipeline 15a\n");
omx_send_command_and_wait(&pi->video_decode, OMX_CommandStateSet, OMX_StateLoaded, NULL);
DEBUGF("[vcodec] omx_teardown pipeline 15b\n");
omx_send_command_and_wait(&pi->video_scheduler, OMX_CommandStateSet, OMX_StateLoaded, NULL);
DEBUGF("[vcodec] omx_teardown pipeline 15c\n");
if (((pi->video_decode.port_settings_changed == 2) && (pi->do_deinterlace)) || (pi->image_fx.port_settings_changed == 2)) {
omx_send_command_and_wait(&pi->video_render, OMX_CommandStateSet, OMX_StateLoaded, NULL);
}
DEBUGF("[vcodec] omx_teardown pipeline 15d\n");
omx_send_command_and_wait(&pi->audio_render, OMX_CommandStateSet, OMX_StateLoaded, NULL);
DEBUGF("[vcodec] omx_teardown pipeline 15e\n");
omx_send_command_and_wait(&pi->clock, OMX_CommandStateSet, OMX_StateLoaded, NULL);
DEBUGF("[vcodec] omx_teardown pipeline 15f\n");
if (pi->do_deinterlace) { omx_send_command_and_wait(&pi->image_fx, OMX_CommandStateSet, OMX_StateLoaded, NULL); }
DEBUGF("[vcodec] omx_teardown pipeline 16\n");
/* Finally free the component handles */
OERR(OMX_FreeHandle(pi->video_decode.h));
OERR(OMX_FreeHandle(pi->video_scheduler.h));
OERR(OMX_FreeHandle(pi->video_render.h));
OERR(OMX_FreeHandle(pi->audio_render.h));
OERR(OMX_FreeHandle(pi->clock.h));
if (pi->do_deinterlace) { OERR(OMX_FreeHandle(pi->image_fx.h)); }
DEBUGF("[vcodec] omx_teardown pipeline 17\n");
}