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 "mmalomx.h"
29#include "mmalomx_buffer.h"
30#include "mmalomx_commands.h"
31#include "mmalomx_marks.h"
32#include "mmalomx_logging.h"
33
34#include <util/mmal_util.h>
35
36/*****************************************************************************/
37OMX_ERRORTYPE mmalomx_buffer_send(
38 MMALOMX_COMPONENT_T *component,
39 OMX_BUFFERHEADERTYPE *omx_buffer,
40 OMX_DIRTYPE direction)
41{
42 OMX_ERRORTYPE status = OMX_ErrorNone;
43 MMAL_BUFFER_HEADER_T *mmal_buffer;
44 MMAL_STATUS_T mmal_status;
45 MMALOMX_PORT_T *port;
46 unsigned int index;
47
48 /* Sanity checks */
49 if (!component)
50 return OMX_ErrorInvalidComponent;
51 if (component->state == OMX_StateInvalid)
52 return OMX_ErrorInvalidState;
53
54 if (!omx_buffer || omx_buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE) ||
55 omx_buffer->nOffset + omx_buffer->nFilledLen > omx_buffer->nAllocLen)
56 return OMX_ErrorBadParameter;
57
58 index = direction == OMX_DirInput ? omx_buffer->nInputPortIndex : omx_buffer->nOutputPortIndex;
59 if (index >= component->ports_num)
60 return OMX_ErrorBadPortIndex;
61
62 port = &component->ports[index];
63 if (port->direction != direction)
64 return OMX_ErrorBadPortIndex;
65
66 MMALOMX_LOCK_PORT(component, port);
67
68 if (component->state != OMX_StatePause && component->state != OMX_StateExecuting)
69 status = OMX_ErrorIncorrectStateOperation;
70 if (!port->enabled /* FIXME: || flushing || pending idle */)
71 status = OMX_ErrorIncorrectStateOperation;
72 if (status != OMX_ErrorNone)
73 goto error;
74
75 mmal_buffer = mmal_queue_get( port->pool->queue );
76 if (!vcos_verify(mmal_buffer)) /* Should never happen */
77 {
78 status = OMX_ErrorUndefined;
79 goto error;
80 }
81
82 mmalomx_mark_process_incoming(component, port, omx_buffer);
83
84 mmal_buffer->user_data = (void *)omx_buffer;
85 mmalil_buffer_header_to_mmal(mmal_buffer, omx_buffer);
86
87 mmal_status = mmal_port_send_buffer(port->mmal, mmal_buffer);
88 if (!vcos_verify(mmal_status == MMAL_SUCCESS))
89 {
90 LOG_ERROR("failed to send buffer on %s", port->mmal->name);
91 mmal_queue_put_back( port->pool->queue, mmal_buffer );
92 status = mmalil_error_to_omx(mmal_status);
93 }
94 else
95 {
96 port->buffers_in_transit++;
97 }
98
99error:
100 MMALOMX_UNLOCK_PORT(component, port);
101 return status;
102}
103
104/*****************************************************************************/
105static void mmalomx_buffer_event(
106 MMALOMX_PORT_T *port,
107 MMAL_BUFFER_HEADER_T *mmal_buffer)
108{
109 MMALOMX_COMPONENT_T *component = port->component;
110 MMAL_EVENT_FORMAT_CHANGED_T *event;
111
112 LOG_TRACE("hComponent %p, port %i, event %4.4s", component, port->index,
113 (char *)&mmal_buffer->cmd);
114
115 if (mmal_buffer->cmd == MMAL_EVENT_ERROR )
116 {
117 mmalomx_callback_event_handler(component, OMX_EventError,
118 mmalil_error_to_omx(*(MMAL_STATUS_T *)mmal_buffer->data), 0, NULL);
119 return;
120 }
121
122 event = mmal_event_format_changed_get(mmal_buffer);
123 if (event && port->mmal->type == MMAL_PORT_TYPE_OUTPUT &&
124 port->mmal->format->type == MMAL_ES_TYPE_VIDEO)
125 {
126 uint32_t diff = mmal_format_compare(event->format, port->mmal->format);
127 MMAL_ES_FORMAT_T *format = port->mmal->format;
128 MMAL_VIDEO_FORMAT_T video = format->es->video;
129
130 /* Update the port settings with the new values */
131 mmal_format_copy(format, event->format);
132 port->mmal->buffer_num_min = event->buffer_num_min;
133 port->mmal->buffer_size_min = event->buffer_size_min;
134 port->format_changed = MMAL_TRUE;
135
136 if ((diff & MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_ASPECT_RATIO) &&
137 /* Do not report a change if going from unspecified to 1:1 */
138 !(format->es->video.par.num == format->es->video.par.den && !video.par.num))
139 {
140 LOG_DEBUG("aspect ratio change %ix%i->%ix%i", (int)video.par.num, (int)video.par.den,
141 (int)format->es->video.par.num, (int)format->es->video.par.den);
142 mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged,
143 port->index, OMX_IndexParamBrcmPixelAspectRatio, NULL);
144 }
145
146 if (diff & (MMAL_ES_FORMAT_COMPARE_FLAG_ENCODING|
147 MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_RESOLUTION|
148 MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_CROPPING))
149 {
150 LOG_DEBUG("format change %ix%i(%ix%i) -> %ix%i(%ix%i)",
151 (int)video.width, (int)video.height,
152 (int)video.crop.width, (int)video.crop.height,
153 (int)format->es->video.width, (int)format->es->video.height,
154 (int)format->es->video.crop.width, (int)format->es->video.crop.height);
155 mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged,
156 port->index, 0, NULL);
157 }
158 }
159 else if (event && port->mmal->type == MMAL_PORT_TYPE_OUTPUT &&
160 port->mmal->format->type == MMAL_ES_TYPE_AUDIO)
161 {
162 uint32_t diff = mmal_format_compare(event->format, port->mmal->format);
163 MMAL_ES_FORMAT_T *format = port->mmal->format;
164 MMAL_AUDIO_FORMAT_T audio = format->es->audio;
165
166 /* Update the port settings with the new values */
167 mmal_format_copy(format, event->format);
168 port->mmal->buffer_num_min = event->buffer_num_min;
169 port->mmal->buffer_size_min = event->buffer_size_min;
170 port->format_changed = MMAL_TRUE;
171
172 if (diff)
173 {
174 LOG_DEBUG("format change %ich, %iHz, %ibps -> %ich, %iHz, %ibps",
175 (int)audio.channels, (int)audio.sample_rate,
176 (int)audio.bits_per_sample,
177 (int)format->es->audio.channels,
178 (int)format->es->audio.sample_rate,
179 (int)format->es->audio.bits_per_sample);
180 mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged,
181 port->index, 0, NULL);
182 }
183 }
184}
185
186/*****************************************************************************/
187OMX_ERRORTYPE mmalomx_buffer_return(
188 MMALOMX_PORT_T *port,
189 MMAL_BUFFER_HEADER_T *mmal_buffer)
190{
191 MMALOMX_COMPONENT_T *component = port->component;
192 OMX_BUFFERHEADERTYPE *omx_buffer = (OMX_BUFFERHEADERTYPE *)mmal_buffer->user_data;
193 MMAL_BOOL_T signal;
194
195 if (mmal_buffer->cmd)
196 {
197 mmalomx_buffer_event(port, mmal_buffer);
198 mmal_buffer_header_release(mmal_buffer);
199 return OMX_ErrorNone;
200 }
201
202 if (ENABLE_MMAL_EXTRA_LOGGING)
203 LOG_TRACE("hComponent %p, port %i, pBuffer %p", component,
204 port->index, omx_buffer);
205
206 vcos_assert(omx_buffer->pBuffer == mmal_buffer->data);
207 mmalil_buffer_header_to_omx(omx_buffer, mmal_buffer);
208 mmal_buffer_header_release(mmal_buffer);
209
210 if ((omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) && port->direction == OMX_DirOutput)
211 {
212 mmalomx_callback_event_handler(component, OMX_EventBufferFlag,
213 port->index, omx_buffer->nFlags, NULL);
214 }
215
216 mmalomx_mark_process_outgoing(component, port, omx_buffer);
217
218 if (port->direction == OMX_DirInput)
219 component->callbacks.EmptyBufferDone((OMX_HANDLETYPE)&component->omx,
220 component->callbacks_data, omx_buffer );
221 else
222 component->callbacks.FillBufferDone((OMX_HANDLETYPE)&component->omx,
223 component->callbacks_data, omx_buffer );
224
225 MMALOMX_LOCK_PORT(component, port);
226 signal = port->actions & MMALOMX_ACTION_CHECK_FLUSHED;
227 port->buffers_in_transit--;
228 MMALOMX_UNLOCK_PORT(component, port);
229
230 if (signal)
231 mmalomx_commands_actions_signal(component);
232
233 return OMX_ErrorNone;
234}
235
236