1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, 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 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON 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 |
25 | SOFTWARE, 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 | /*****************************************************************************/ |
37 | OMX_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 | |
99 | error: |
100 | MMALOMX_UNLOCK_PORT(component, port); |
101 | return status; |
102 | } |
103 | |
104 | /*****************************************************************************/ |
105 | static 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 | /*****************************************************************************/ |
187 | OMX_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 | |