1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "bcm_host.h"
29
30#include "mmal.h"
31#include "util/mmal_connection.h"
32#include "util/mmal_default_components.h"
33#include "util/mmal_util_params.h"
34#include "interface/vcos/vcos.h"
35#include <stdio.h>
36
37#define CHECK_STATUS(status, msg) if (status != MMAL_SUCCESS) { fprintf(stderr, msg"\n"); goto error; }
38
39/** Context for our application */
40static struct CONTEXT_T {
41 VCOS_SEMAPHORE_T semaphore;
42 MMAL_STATUS_T status;
43 MMAL_BOOL_T eos;
44} context;
45
46/** Callback from a control port. Error and EOS events stop playback. */
47static void control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
48{
49 struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata;
50
51 if (buffer->cmd == MMAL_EVENT_ERROR)
52 ctx->status = *(MMAL_STATUS_T *)buffer->data;
53 else if (buffer->cmd == MMAL_EVENT_EOS)
54 ctx->eos = MMAL_TRUE;
55
56 mmal_buffer_header_release(buffer);
57
58 /* The processing is done in our main thread */
59 vcos_semaphore_post(&ctx->semaphore);
60}
61
62/** Callback from the connection. Buffer is available. */
63static void connection_callback(MMAL_CONNECTION_T *connection)
64{
65 struct CONTEXT_T *ctx = (struct CONTEXT_T *)connection->user_data;
66
67 /* The processing is done in our main thread */
68 vcos_semaphore_post(&ctx->semaphore);
69}
70
71int main(int argc, char **argv)
72{
73 MMAL_STATUS_T status;
74 MMAL_COMPONENT_T *reader = 0, *decoder = 0, *renderer = 0;
75 MMAL_CONNECTION_T *connection[2] = {0};
76 unsigned int i, count, connection_num = vcos_countof(connection);
77
78 if (argc < 2)
79 {
80 fprintf(stderr, "invalid arguments\n");
81 return -1;
82 }
83
84 bcm_host_init();
85
86 vcos_semaphore_create(&context.semaphore, "example", 1);
87
88 /* Create the components */
89 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CONTAINER_READER, &reader);
90 CHECK_STATUS(status, "failed to create reader");
91 reader->control->userdata = (void *)&context;
92 status = mmal_port_enable(reader->control, control_callback);
93 CHECK_STATUS(status, "failed to enable control port");
94 status = mmal_component_enable(reader);
95 CHECK_STATUS(status, "failed to enable component");
96
97 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder);
98 CHECK_STATUS(status, "failed to create decoder");
99 decoder->control->userdata = (void *)&context;
100 status = mmal_port_enable(decoder->control, control_callback);
101 CHECK_STATUS(status, "failed to enable control port");
102 status = mmal_component_enable(decoder);
103 CHECK_STATUS(status, "failed to enable component");
104
105 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &renderer);
106 CHECK_STATUS(status, "failed to create renderer");
107 renderer->control->userdata = (void *)&context;
108 status = mmal_port_enable(renderer->control, control_callback);
109 CHECK_STATUS(status, "failed to enable control port");
110 status = mmal_component_enable(renderer);
111 CHECK_STATUS(status, "failed to enable component");
112
113 /* Configure the reader using the given URI */
114 status = mmal_util_port_set_uri(reader->control, argv[1]);
115 CHECK_STATUS(status, "failed to set uri");
116
117 /* Create the connections between the components */
118 status = mmal_connection_create(&connection[0], reader->output[0], decoder->input[0], 0);
119 CHECK_STATUS(status, "failed to create connection between reader / decoder");
120 connection[0]->user_data = &context;
121 connection[0]->callback = connection_callback;
122 status = mmal_connection_create(&connection[1], decoder->output[0], renderer->input[0], 0);
123 CHECK_STATUS(status, "failed to create connection between decoder / renderer");
124 connection[1]->user_data = &context;
125 connection[1]->callback = connection_callback;
126
127 /* Enable all our connections */
128 for (i = connection_num; i; i--)
129 {
130 status = mmal_connection_enable(connection[i-1]);
131 CHECK_STATUS(status, "failed to enable connection");
132 }
133
134 /* Start playback */
135 fprintf(stderr, "start playback\n");
136
137 /* This is the main processing loop */
138 for (count = 0; count < 500; count++)
139 {
140 MMAL_BUFFER_HEADER_T *buffer;
141 vcos_semaphore_wait(&context.semaphore);
142
143 /* Check for errors */
144 status = context.status;
145 CHECK_STATUS(status, "error during playback");
146
147 /* Check for end of stream */
148 if (context.eos)
149 break;
150
151 /* Handle buffers for all our connections */
152 for (i = 0; i < connection_num; i++)
153 {
154 if (connection[i]->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
155 continue; /* Nothing else to do in tunnelling mode */
156
157 /* Send empty buffers to the output port of the connection */
158 while ((buffer = mmal_queue_get(connection[i]->pool->queue)) != NULL)
159 {
160 status = mmal_port_send_buffer(connection[i]->out, buffer);
161 CHECK_STATUS(status, "failed to send buffer");
162 }
163
164 /* Send any queued buffer to the next component */
165 while ((buffer = mmal_queue_get(connection[i]->queue)) != NULL)
166 {
167 status = mmal_port_send_buffer(connection[i]->in, buffer);
168 CHECK_STATUS(status, "failed to send buffer");
169 }
170 }
171 }
172
173 /* Stop everything */
174 fprintf(stderr, "stop playback\n");
175 for (i = 0; i < connection_num; i++)
176 {
177 mmal_connection_disable(connection[i]);
178 }
179
180 error:
181 /* Cleanup everything */
182 for (i = 0; i < connection_num; i++)
183 {
184 if (connection[i])
185 mmal_connection_destroy(connection[i]);
186 }
187 if (reader)
188 mmal_component_destroy(reader);
189 if (decoder)
190 mmal_component_destroy(decoder);
191 if (renderer)
192 mmal_component_destroy(renderer);
193
194 vcos_semaphore_delete(&context.semaphore);
195 return status == MMAL_SUCCESS ? 0 : -1;
196}
197