Esempio n. 1
0
struct window *window_setup(struct registry *registry, uint32_t width, uint32_t height, bool shell_surface) {
	struct window *window = malloc(sizeof(struct window));
	memset(window, 0, sizeof(struct window));
	window->width = width;
	window->height = height;
	window->registry = registry;
	window->font = "monospace 10";

	window->surface = wl_compositor_create_surface(registry->compositor);
	if (shell_surface) {
		window->shell_surface = wl_shell_get_shell_surface(registry->shell, window->surface);
		wl_shell_surface_add_listener(window->shell_surface, &surface_listener, window);
		wl_shell_surface_set_toplevel(window->shell_surface);
	}
	if (registry->pointer) {
		wl_pointer_add_listener(registry->pointer, &pointer_listener, window);
	}

	get_next_buffer(window);

	window->cursor.cursor_theme = wl_cursor_theme_load("default", 32, registry->shm); // TODO: let you customize this
	window->cursor.cursor = wl_cursor_theme_get_cursor(window->cursor.cursor_theme, "left_ptr");
	window->cursor.surface = wl_compositor_create_surface(registry->compositor);

	struct wl_cursor_image *image = window->cursor.cursor->images[0];
	struct wl_buffer *cursor_buf = wl_cursor_image_get_buffer(image);
	wl_surface_attach(window->cursor.surface, cursor_buf, 0, 0);
	wl_surface_damage(window->cursor.surface, 0, 0, image->width, image->height);
	wl_surface_commit(window->cursor.surface);

	return window;
}
Esempio n. 2
0
static void print_buffers(void)
{
	struct print_buffer *buffer;
	struct entry_head *head;
	off_t read_pos;
	int len;

	while (1) {
		buffer = get_next_buffer();
		if (!buffer)
			break;

		read_pos = buffer->read_pos;
		head = buffer->ring + read_pos;
		len = strlen(head->text);

		if (len) {
			/* Print out non-empty entry and proceed */
			fprintf(head->dest, "%s", head->text);
			read_pos += sizeof(*head) + len;
		} else {
			/* Emptry entries mark the wrap-around */
			read_pos = 0;
		}

		/* Make sure we have read the entry competely before
		   forwarding read_pos */
		xnarch_read_memory_barrier();
		buffer->read_pos = read_pos;

		/* Enforce the read_pos update before proceeding */
		xnarch_write_memory_barrier();
	}
}
Esempio n. 3
0
int window_prerender(struct window *window) {
	if (window->frame_cb) {
		return 0;
	}

	get_next_buffer(window);
	return 1;
}
Esempio n. 4
0
_TCHAR * get_nice_number( __int64 num, size_t width )
{
   size_t len, i;
   _TCHAR * pb1 = get_next_buffer();
   _TCHAR * pb2 = get_next_buffer();
   SPRINTF(pb1, "%lld", num);
   nice_num( pb2, pb1 );
   len = STRLEN(pb2);
   if( len < width )
   {
      *pb1 = 0;
      i = width - len;  // get pad
      while(i--)
         STRCAT(pb1, " ");
      STRCAT(pb1,pb2);
      pb2 = pb1;
   }
   return pb2;
}
Esempio n. 5
0
void render_frame(struct swaynag *swaynag) {
	if (!swaynag->run_display) {
		return;
	}

	cairo_surface_t *recorder = cairo_recording_surface_create(
			CAIRO_CONTENT_COLOR_ALPHA, NULL);
	cairo_t *cairo = cairo_create(recorder);
	cairo_save(cairo);
	cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
	cairo_paint(cairo);
	cairo_restore(cairo);
	uint32_t height = render_to_cairo(cairo, swaynag);
	if (height != swaynag->height) {
		zwlr_layer_surface_v1_set_size(swaynag->layer_surface, 0, height);
		zwlr_layer_surface_v1_set_exclusive_zone(swaynag->layer_surface,
				height);
		wl_surface_commit(swaynag->surface);
		wl_display_roundtrip(swaynag->display);
	} else {
		swaynag->current_buffer = get_next_buffer(swaynag->shm,
				swaynag->buffers,
				swaynag->width * swaynag->scale,
				swaynag->height * swaynag->scale);
		if (!swaynag->current_buffer) {
			sway_log(SWAY_DEBUG, "Failed to get buffer. Skipping frame.");
			goto cleanup;
		}

		cairo_t *shm = swaynag->current_buffer->cairo;
		cairo_save(shm);
		cairo_set_operator(shm, CAIRO_OPERATOR_CLEAR);
		cairo_paint(shm);
		cairo_restore(shm);
		cairo_set_source_surface(shm, recorder, 0.0, 0.0);
		cairo_paint(shm);

		wl_surface_set_buffer_scale(swaynag->surface, swaynag->scale);
		wl_surface_attach(swaynag->surface,
				swaynag->current_buffer->buffer, 0, 0);
		wl_surface_damage(swaynag->surface, 0, 0,
				swaynag->width, swaynag->height);
		wl_surface_commit(swaynag->surface);
		wl_display_roundtrip(swaynag->display);
	}

cleanup:
	cairo_surface_destroy(recorder);
	cairo_destroy(cairo);
}
Esempio n. 6
0
void force_thread_flush(per_thread_t *tcxt)
{
    if(tcxt->has_channel_lock)
    {
        uint channel_idx = tcxt->thread_id % clo.frontend_threads;
        ipc_channel_t *channel = &IPC[channel_idx];
        notify_full_buffer(channel);
        get_next_buffer(channel);
        ordered_unlock(channel);
        tcxt->has_channel_lock = false;
        SGLEV_PTR(tcxt->seg_base) = NULL;
        SGLEND_PTR(tcxt->seg_base) = NULL;
        SGLUSED_PTR(tcxt->seg_base) = NULL;
    }
}
Esempio n. 7
0
struct window *window_setup(struct registry *registry, uint32_t width, uint32_t height,
		int32_t scale, bool shell_surface) {
	struct window *window = malloc(sizeof(struct window));
	memset(window, 0, sizeof(struct window));
	window->width = width;
	window->height = height;
	window->scale = scale;
	window->registry = registry;
	window->font = "monospace 10";

	window->surface = wl_compositor_create_surface(registry->compositor);
	if (shell_surface) {
		window_make_shell(window);
	}
	if (registry->pointer) {
		wl_pointer_add_listener(registry->pointer, &pointer_listener, window);
	}

	get_next_buffer(window);

	if (registry->pointer) {
		char *cursor_theme = getenv("SWAY_CURSOR_THEME");
		if (!cursor_theme) {
			cursor_theme = "default";
		}
		char *cursor_size = getenv("SWAY_CURSOR_SIZE");
		if (!cursor_size) {
			cursor_size = "16";
		}

		sway_log(L_DEBUG, "Cursor scale: %d", scale);
		window->cursor.cursor_theme = wl_cursor_theme_load(cursor_theme,
				atoi(cursor_size) * scale, registry->shm);
		window->cursor.cursor = wl_cursor_theme_get_cursor(window->cursor.cursor_theme, "left_ptr");
		window->cursor.surface = wl_compositor_create_surface(registry->compositor);

		struct wl_cursor_image *image = window->cursor.cursor->images[0];
		struct wl_buffer *cursor_buf = wl_cursor_image_get_buffer(image);
		wl_surface_attach(window->cursor.surface, cursor_buf, 0, 0);
		wl_surface_set_buffer_scale(window->cursor.surface, scale);
		wl_surface_damage(window->cursor.surface, 0, 0,
				image->width, image->height);
		wl_surface_commit(window->cursor.surface);
	}

	return window;
}
Esempio n. 8
0
static void print_buffers(void)
{
	struct print_buffer *buffer;
	struct entry_head *head;
	off_t read_pos;
	int len, ret;

	while (1) {
		buffer = get_next_buffer();
		if (!buffer)
			break;

		read_pos = buffer->read_pos;
		head = buffer->ring + read_pos;
		len = head->len;

		if (len) {
			/* Print out non-empty entry and proceed */
			/* Check if output goes to syslog */
			if (head->dest == RT_PRINT_SYSLOG_STREAM) {
				syslog(head->priority,
				       "%s", head->data);
			} else {
				ret = fwrite(head->data,
					     head->len, 1, head->dest);
				(void)ret;
			}

			read_pos += sizeof(*head) + len;
		} else {
			/* Emptry entries mark the wrap-around */
			read_pos = 0;
		}

		/* Make sure we have read the entry competely before
		   forwarding read_pos */
		smp_rmb();
		buffer->read_pos = read_pos;

		/* Enforce the read_pos update before proceeding */
		smp_wmb();
	}
}
Esempio n. 9
0
static inline EventBuffer*
get_buffer(ipc_channel_t *channel, uint required)
{
    /* Check if enough space is available in the current buffer */
    EventBuffer *current_shmem_buffer = channel->shared_mem->eventBuffers +
                                        channel->shmem_buf_idx;
    uint available = SIGIL2_EVENTS_BUFFER_SIZE - current_shmem_buffer->used;

    if(available < required)
    {
        /* First inform Sigil2 the current buffer can be read */
        notify_full_buffer(channel);

        /* Then get a new buffer for writing */
        current_shmem_buffer = get_next_buffer(channel);
    }

    return current_shmem_buffer;
}
Esempio n. 10
0
int		get_next_line(int const fd, char **line)
{
	static char			overf[MAX_FD][BUFF_SIZE + 1];
	int					ret;

	if (fd < 0 || fd > MAX_FD || !line)
		return (-1);
	*line = NULL;
	if (overf[fd][0])
	{
		ret = get_overf(line, overf[fd]);
		if (ret != 0)
			return (ret);
	}
	ret = get_next_buffer(line, overf[fd], fd);
	if (ret == -1)
		return (-1);
	return (*line != NULL);
}
Esempio n. 11
0
_TCHAR * get_k_num( __int64 i64, int ascii, int type )
{
   int dotrim = 1;
   _TCHAR * pb = get_next_buffer();
   _TCHAR * form = " bytes";
   __int64 byts = i64;
   double res;
   _TCHAR * ffm = "%0.20f";  // get 20 digits
   if( byts < 1024 ) {
      SPRINTF(pb, "%llu", byts);
      dotrim = 0;
   } else if( byts < 1024*1024 ) {
      res = ((double)byts / 1024.0);
      form = (type ? " KiloBypes" : " KB");
      SPRINTF(pb, ffm, res);
   } else if( byts < 1024*1024*1024 ) {
      res = ((double)byts / (1024.0*1024.0));
      form = (type ? " MegaBypes" : " MB");
      SPRINTF(pb, ffm, res);
   } else { // if( byts <  (1024*1024*1024*1024)){
      double val = (double)byts;
      double db = (1024.0*1024.0*1024.0);   // x3
      double db2 = (1024.0*1024.0*1024.0*1024.0);   // x4
      if( val < db2 )
      {
         res = val / db;
         form = (type ? " GigaBypes" : " GB");
         SPRINTF(pb, ffm, res);
      }
      else
      {
         db *= 1024.0;  // x4
         db2 *= 1024.0; // x5
         if( val < db2 )
         {
            res = val / db;
            form = (type ? " TeraBypes" : " TB");
            SPRINTF(pb, ffm, res);
         }
         else
         {
            db *= 1024.0;  // x5
            db2 *= 1024.0; // x6
            if( val < db2 )
            {
               res = val / db;
               form = (type ? " PetaBypes" : " PB");
               SPRINTF(pb, ffm, res);
            }
            else
            {
               db *= 1024.0;  // x6
               db2 *= 1024.0; // x7
               if( val < db2 )
               {
                  res = val / db;
                  form = (type ? " ExaBypes" : " EB");
                  SPRINTF(pb, ffm, res);
               }
               else
               {
                  db *= 1024.0;  // x7
                  res = val / db;
                  form = (type ? " ZettaBypes" : " ZB");
                  SPRINTF(pb, ffm, res);
               }
            }
         }
      }
   }
   if( dotrim > 0 )
      trim_float_buf(pb);

   STRCAT(pb, form);

   //if( ascii > 0 )
   //   Convert_2_ASCII(pb);

   return pb;
}
Esempio n. 12
0
void source_main (source_t *source)
{
    refbuf_t *refbuf;
    client_t *client;
    avl_node *client_node;

    source_init (source);

    while (global.running == ICE_RUNNING && source->running) {
        int remove_from_q;

        refbuf = get_next_buffer (source);

        remove_from_q = 0;
        source->short_delay = 0;

        if (refbuf)
        {
            /* append buffer to the in-flight data queue,  */
            if (source->stream_data == NULL)
            {
                source->stream_data = refbuf;
                source->burst_point = refbuf;
            }
            if (source->stream_data_tail)
                source->stream_data_tail->next = refbuf;
            source->stream_data_tail = refbuf;
            source->queue_size += refbuf->len;
            /* new buffer is referenced for burst */
            refbuf_addref (refbuf);

            /* new data on queue, so check the burst point */
            source->burst_offset += refbuf->len;
            while (source->burst_offset > source->burst_size)
            {
                refbuf_t *to_release = source->burst_point;

                if (to_release->next)
                {
                    source->burst_point = to_release->next;
                    source->burst_offset -= to_release->len;
                    refbuf_release (to_release);
                    continue;
                }
                break;
            }

            /* save stream to file */
            if (source->dumpfile && source->format->write_buf_to_file)
                source->format->write_buf_to_file (source, refbuf);
        }
        /* lets see if we have too much data in the queue, but don't remove it until later */
        if (source->queue_size > source->queue_size_limit)
            remove_from_q = 1;

        /* acquire write lock on pending_tree */
        avl_tree_wlock(source->pending_tree);

        /* acquire write lock on client_tree */
        avl_tree_wlock(source->client_tree);

        client_node = avl_get_first(source->client_tree);
        while (client_node) {
            client = (client_t *)client_node->key;

            send_to_listener (source, client, remove_from_q);

            if (client->con->error) {
                client_node = avl_get_next(client_node);
                if (client->respcode == 200)
                    stats_event_dec (NULL, "listeners");
                avl_delete(source->client_tree, (void *)client, _free_client);
                source->listeners--;
                DEBUG0("Client removed");
                continue;
            }
            client_node = avl_get_next(client_node);
        }

        /** add pending clients **/
        client_node = avl_get_first(source->pending_tree);
        while (client_node) {

            if(source->max_listeners != -1 && 
                    source->listeners >= (unsigned long)source->max_listeners) 
            {
                /* The common case is caught in the main connection handler,
                 * this deals with rarer cases (mostly concerning fallbacks)
                 * and doesn't give the listening client any information about
                 * why they were disconnected
                 */
                client = (client_t *)client_node->key;
                client_node = avl_get_next(client_node);
                avl_delete(source->pending_tree, (void *)client, _free_client);

                INFO0("Client deleted, exceeding maximum listeners for this "
                        "mountpoint.");
                continue;
            }
            
            /* Otherwise, the client is accepted, add it */
            avl_insert(source->client_tree, client_node->key);

            source->listeners++;
            DEBUG0("Client added");
            stats_event_inc(source->mount, "connections");

            client_node = avl_get_next(client_node);
        }

        /** clear pending tree **/
        while (avl_get_first(source->pending_tree)) {
            avl_delete(source->pending_tree, 
                    avl_get_first(source->pending_tree)->key, 
                    source_remove_client);
        }

        /* release write lock on pending_tree */
        avl_tree_unlock(source->pending_tree);

        /* update the stats if need be */
        if (source->listeners != source->prev_listeners)
        {
            source->prev_listeners = source->listeners;
            INFO2("listener count on %s now %lu", source->mount, source->listeners);
            if (source->listeners > source->peak_listeners)
            {
                source->peak_listeners = source->listeners;
                stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
            }
            stats_event_args (source->mount, "listeners", "%lu", source->listeners);
            if (source->listeners == 0 && source->on_demand)
                source->running = 0;
        }

        /* lets reduce the queue, any lagging clients should of been
         * terminated by now
         */
        if (source->stream_data)
        {
            /* normal unreferenced queue data will have a refcount 1, but
             * burst queue data will be at least 2, active clients will also
             * increase refcount */
            while (source->stream_data->_count == 1)
            {
                refbuf_t *to_go = source->stream_data;

                if (to_go->next == NULL || source->burst_point == to_go)
                {
                    /* this should not happen */
                    ERROR0 ("queue state is unexpected");
                    source->running = 0;
                    break;
                }
                source->stream_data = to_go->next;
                source->queue_size -= to_go->len;
                to_go->next = NULL;
                refbuf_release (to_go);
            }
        }

        /* release write lock on client_tree */
        avl_tree_unlock(source->client_tree);
    }
    source_shutdown (source);
}
Esempio n. 13
0
void omx_teardown_pipeline(struct omx_pipeline_t* pipe)
{
   OMX_BUFFERHEADERTYPE *buf;
   int i=1;

   DEBUGF("[vcodec] omx_teardown pipeline:\n");
   DEBUGF("pipe->video_decode.port_settings_changed = %d\n",pipe->video_decode.port_settings_changed);
   DEBUGF("pipe->image_fx.port_settings_changed = %d\n",pipe->image_fx.port_settings_changed);
   DEBUGF("pipe->video_scheduler.port_settings_changed = %d\n",pipe->video_scheduler.port_settings_changed);
   //dumpport(pipe->video_decode.h,130);

#if 0
   /* Indicate end of video stream */
   buf = get_next_buffer(&pipe->video_decode);

   buf->nFilledLen = 0;
   buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
   
   OERR(OMX_EmptyThisBuffer(pipe->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(&pipe->video_decode.eos_mutex);
   while (!pipe->video_decode.eos)
     pthread_cond_wait(&pipe->video_decode.eos_cv,&pipe->video_decode.eos_mutex);
   pthread_mutex_unlock(&pipe->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(&pipe->video_decode, OMX_CommandStateSet, OMX_StateIdle, NULL); 
   omx_send_command_and_wait(&pipe->clock, OMX_CommandStateSet, OMX_StateIdle, NULL);
   DEBUGF("pipe->do_deinterlace=%d, pipe->image_fx=%d\n",pipe->do_deinterlace,(int)pipe->image_fx.h);
   if (pipe->video_decode.port_settings_changed == 2) {
      if (pipe->do_deinterlace) { 
        omx_send_command_and_wait(&pipe->image_fx, OMX_CommandStateSet, OMX_StateIdle, NULL); 
      } else {
        omx_send_command_and_wait(&pipe->video_scheduler, OMX_CommandStateSet, OMX_StateIdle, NULL); 
      }
   }
   if (pipe->image_fx.port_settings_changed == 2) {
     omx_send_command_and_wait(&pipe->video_scheduler, OMX_CommandStateSet, OMX_StateIdle, NULL);
   }
   if (pipe->video_scheduler.port_settings_changed == 2) {
     omx_send_command_and_wait(&pipe->video_render, OMX_CommandStateSet, OMX_StateIdle, NULL);
   }
   omx_send_command_and_wait(&pipe->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(&pipe->video_render.eos_mutex);
   while (!pipe->video_render.eos)
     pthread_cond_wait(&pipe->video_render.eos_cv,&pipe->video_render.eos_mutex);
   pthread_mutex_unlock(&pipe->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(&pipe->video_decode,OMX_CommandFlush,130,NULL);
   omx_send_command_and_wait(&pipe->audio_render,OMX_CommandFlush,100,NULL);

   /* Flush all tunnels */
   DEBUGF("[vcodec] omx_teardown pipeline 3\n");
   if (pipe->do_deinterlace) {
     omx_flush_tunnel(&pipe->video_decode, 131, &pipe->image_fx, 190);
     omx_flush_tunnel(&pipe->image_fx, 191, &pipe->video_scheduler, 10);
   } else {
     omx_flush_tunnel(&pipe->video_decode, 131, &pipe->video_scheduler, 10);
   }
   DEBUGF("[vcodec] omx_teardown pipeline 4\n");
   omx_flush_tunnel(&pipe->video_scheduler, 11, &pipe->video_render, 90);
   omx_flush_tunnel(&pipe->clock, 81, &pipe->video_scheduler, 12);

   DEBUGF("[vcodec] omx_teardown pipeline 2b\n");

   omx_send_command_and_wait(&pipe->video_scheduler,OMX_CommandFlush,10,NULL);
   DEBUGF("[vcodec] omx_teardown pipeline 5\n");

   omx_flush_tunnel(&pipe->clock, 80, &pipe->audio_render, 101);

   /* Disable audio_render input port and buffers */
   omx_send_command_and_wait0(&pipe->audio_render, OMX_CommandPortDisable, 100, NULL);
   omx_free_buffers(&pipe->audio_render, 100);
   omx_send_command_and_wait1(&pipe->audio_render, OMX_CommandPortDisable, 100, NULL);
   DEBUGF("[vcodec] omx_teardown pipeline 9\n");

   /* Scheduler -> render tunnel */
   if (pipe->video_scheduler.port_settings_changed == 2) {
     omx_send_command_and_wait(&pipe->video_scheduler, OMX_CommandPortDisable, 11, NULL);
     omx_send_command_and_wait(&pipe->video_render, OMX_CommandPortDisable, 90, NULL);

     omx_send_command_and_wait(&pipe->video_scheduler, OMX_CommandPortDisable, 10, NULL);
   }

   if ((pipe->image_fx.port_settings_changed == 2) && (pipe->do_deinterlace)) {
     omx_send_command_and_wait(&pipe->image_fx, OMX_CommandPortDisable, 190, NULL);
     omx_send_command_and_wait(&pipe->image_fx, OMX_CommandPortDisable, 191, NULL);
   }

   DEBUGF("[vcodec] omx_teardown pipeline 8a\n");

   //dumpport(pipe->video_scheduler.h,10);

   /* 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(pipe->video_decode.h,131);
   OERR(OMX_SetupTunnel(pipe->video_scheduler.h, 10, NULL, 0));

   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(pipe->clock.h, OMX_CommandPortDisable, 80, NULL));
   omx_send_command_and_wait(&pipe->audio_render, OMX_CommandPortDisable, 101, NULL);
   OERR(OMX_SendCommand(pipe->clock.h, OMX_CommandPortDisable, 81, NULL));
   omx_send_command_and_wait(&pipe->video_scheduler, OMX_CommandPortDisable, 12, NULL);

   DEBUGF("[vcodec] omx_teardown pipeline 12b\n");

   if (pipe->do_deinterlace) {
     OERR(OMX_SetupTunnel(pipe->image_fx.h, 190, NULL, 0));
     OERR(OMX_SetupTunnel(pipe->image_fx.h, 191, NULL, 0));
   }

   DEBUGF("[vcodec] omx_teardown pipeline 13\n");

   OERR(OMX_SetupTunnel(pipe->video_scheduler.h, 11, NULL, 0));
   OERR(OMX_SetupTunnel(pipe->video_render.h, 90, NULL, 0));

   OERR(OMX_SetupTunnel(pipe->clock.h, 81, NULL, 0));
   OERR(OMX_SetupTunnel(pipe->video_scheduler.h, 12, NULL, 0));

   DEBUGF("[vcodec] omx_teardown pipeline 13b\n");

   OERR(OMX_SetupTunnel(pipe->clock.h, 80, NULL, 0));
   OERR(OMX_SetupTunnel(pipe->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
*/

   omx_show_state(&pipe->video_decode,130,131,0);
   dumpport(pipe->video_decode.h,131);
   omx_show_state(&pipe->video_scheduler,10,11,12);
   if (pipe->do_deinterlace) { omx_show_state(&pipe->image_fx,190,191,0); }
   omx_show_state(&pipe->video_render,90,0,0);
   omx_show_state(&pipe->audio_render,100,101,0);
   omx_show_state(&pipe->clock,80,81,0);

   if (pipe->video_decode.port_settings_changed == 2) {
     //dumpport(pipe->video_decode.h,131);
     omx_send_command_and_wait(&pipe->video_decode, OMX_CommandPortDisable, 131, NULL);
   }

   DEBUGF("[vcodec] omx_teardown pipeline 11\n");

   /* Disable video_decode input port and buffers */
   //dumpport(pipe->video_decode.h,130);
   omx_send_command_and_wait0(&pipe->video_decode, OMX_CommandPortDisable, 130, NULL);
   DEBUGF("[vcodec] omx_teardown pipeline 6\n");
   omx_free_buffers(&pipe->video_decode, 130);
   DEBUGF("[vcodec] omx_teardown pipeline 7\n");
   //omx_send_command_and_wait1(&pipe->video_decode, OMX_CommandPortDisable, 130, NULL);

   //dumpport(pipe->video_decode.h,130);
   if (is_port_enabled(pipe->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(pipe->video_decode.h, 131, NULL, 0));

   DEBUGF("[vcodec] omx_teardown pipeline 15\n");

   omx_show_state(&pipe->video_decode,130,131,0);

   /* Transition all components to Loaded */
   DEBUGF("[vcodec] omx_teardown pipeline 15a\n");
   omx_send_command_and_wait(&pipe->video_decode, OMX_CommandStateSet, OMX_StateLoaded, NULL);
   DEBUGF("[vcodec] omx_teardown pipeline 15b\n");
   omx_send_command_and_wait(&pipe->video_scheduler, OMX_CommandStateSet, OMX_StateLoaded, NULL);
   DEBUGF("[vcodec] omx_teardown pipeline 15c\n");
   if (((pipe->video_decode.port_settings_changed == 2) && (pipe->do_deinterlace)) || (pipe->image_fx.port_settings_changed == 2)) {
     omx_send_command_and_wait(&pipe->video_render, OMX_CommandStateSet, OMX_StateLoaded, NULL);
   }
   DEBUGF("[vcodec] omx_teardown pipeline 15d\n");
   omx_send_command_and_wait(&pipe->audio_render, OMX_CommandStateSet, OMX_StateLoaded, NULL);
   DEBUGF("[vcodec] omx_teardown pipeline 15e\n");
   omx_send_command_and_wait(&pipe->clock, OMX_CommandStateSet, OMX_StateLoaded, NULL);
   DEBUGF("[vcodec] omx_teardown pipeline 15f\n");
   if (pipe->do_deinterlace) { omx_send_command_and_wait(&pipe->image_fx, OMX_CommandStateSet, OMX_StateLoaded, NULL); }

   DEBUGF("[vcodec] omx_teardown pipeline 16\n");
   /* Finally free the component handles */
   OERR(OMX_FreeHandle(pipe->video_decode.h));
   OERR(OMX_FreeHandle(pipe->video_scheduler.h));
   OERR(OMX_FreeHandle(pipe->video_render.h));
   OERR(OMX_FreeHandle(pipe->audio_render.h));
   OERR(OMX_FreeHandle(pipe->clock.h));
   if (pipe->do_deinterlace) { OERR(OMX_FreeHandle(pipe->image_fx.h)); }
   DEBUGF("[vcodec] omx_teardown pipeline 17\n");
}