Initial version of libomxil-vc4 for RPI3
[platform/adaptation/broadcom/libomxil-vc4.git] / interface / mmal / openmaxil / mmalomx_buffer.c
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