| 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 | |