mmal/codec: Remove useless locking
[vlc.git] / modules / hw / mmal / codec.c
blob336dde04f194f386c2ee10e746e185ba3d7d50ea
1 /*****************************************************************************
2 * mmal.c: MMAL-based decoder plugin for Raspberry Pi
3 *****************************************************************************
4 * Copyright © 2014 jusst technologies GmbH
5 * $Id$
7 * Authors: Dennis Hamester <dennis.hamester@gmail.com>
8 * Julian Scheel <julian@jusst.de>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 #include <vlc_common.h>
30 #include <vlc_atomic.h>
31 #include <vlc_plugin.h>
32 #include <vlc_codec.h>
33 #include <vlc_threads.h>
35 #include <bcm_host.h>
36 #include <interface/mmal/mmal.h>
37 #include <interface/mmal/util/mmal_util.h>
38 #include <interface/mmal/util/mmal_default_components.h>
40 #include "mmal_picture.h"
43 * This seems to be a bit high, but reducing it causes instabilities
45 #define NUM_EXTRA_BUFFERS 20
46 #define NUM_DECODER_BUFFER_HEADERS 20
48 #define MIN_NUM_BUFFERS_IN_TRANSIT 2
50 #define MMAL_OPAQUE_NAME "mmal-opaque"
51 #define MMAL_OPAQUE_TEXT N_("Decode frames directly into RPI VideoCore instead of host memory.")
52 #define MMAL_OPAQUE_LONGTEXT N_("Decode frames directly into RPI VideoCore instead of host memory. This option must only be used with the MMAL video output plugin.")
54 static int OpenDecoder(decoder_t *dec);
55 static void CloseDecoder(decoder_t *dec);
57 vlc_module_begin()
58 set_shortname(N_("MMAL decoder"))
59 set_description(N_("MMAL-based decoder plugin for Raspberry Pi"))
60 set_capability("video decoder", 90)
61 add_shortcut("mmal_decoder")
62 add_bool(MMAL_OPAQUE_NAME, true, MMAL_OPAQUE_TEXT, MMAL_OPAQUE_LONGTEXT, false)
63 set_callbacks(OpenDecoder, CloseDecoder)
64 vlc_module_end()
66 struct decoder_sys_t {
67 bool opaque;
68 MMAL_COMPONENT_T *component;
69 MMAL_PORT_T *input;
70 MMAL_POOL_T *input_pool;
71 MMAL_PORT_T *output;
72 MMAL_POOL_T *output_pool; /* only used for non-opaque mode */
73 MMAL_ES_FORMAT_T *output_format;
74 MMAL_QUEUE_T *decoded_pictures;
75 vlc_sem_t sem;
77 bool b_top_field_first;
78 bool b_progressive;
80 /* statistics */
81 int output_in_transit;
82 int input_in_transit;
83 atomic_bool started;
86 /* Utilities */
87 static int change_output_format(decoder_t *dec);
88 static int send_output_buffer(decoder_t *dec);
89 static void fill_output_port(decoder_t *dec);
91 /* VLC decoder callback */
92 static int decode(decoder_t *dec, block_t *block);
93 static void flush_decoder(decoder_t *dec);
95 /* MMAL callbacks */
96 static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
97 static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
98 static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
100 static int OpenDecoder(decoder_t *dec)
102 int ret = VLC_SUCCESS;
103 decoder_sys_t *sys;
104 MMAL_PARAMETER_UINT32_T extra_buffers;
105 MMAL_STATUS_T status;
107 if (dec->fmt_in.i_codec != VLC_CODEC_MPGV &&
108 dec->fmt_in.i_codec != VLC_CODEC_H264)
109 return VLC_EGENERIC;
111 sys = calloc(1, sizeof(decoder_sys_t));
112 if (!sys) {
113 ret = VLC_ENOMEM;
114 goto out;
116 dec->p_sys = sys;
118 sys->opaque = var_InheritBool(dec, MMAL_OPAQUE_NAME);
119 bcm_host_init();
121 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &sys->component);
122 if (status != MMAL_SUCCESS) {
123 msg_Err(dec, "Failed to create MMAL component %s (status=%"PRIx32" %s)",
124 MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status));
125 ret = VLC_EGENERIC;
126 goto out;
129 sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
130 status = mmal_port_enable(sys->component->control, control_port_cb);
131 if (status != MMAL_SUCCESS) {
132 msg_Err(dec, "Failed to enable control port %s (status=%"PRIx32" %s)",
133 sys->component->control->name, status, mmal_status_to_string(status));
134 ret = VLC_EGENERIC;
135 goto out;
138 sys->input = sys->component->input[0];
139 sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
140 if (dec->fmt_in.i_codec == VLC_CODEC_MPGV)
141 sys->input->format->encoding = MMAL_ENCODING_MP2V;
142 else
143 sys->input->format->encoding = MMAL_ENCODING_H264;
145 if (dec->fmt_in.i_codec == VLC_CODEC_H264) {
146 if (dec->fmt_in.i_extra > 0) {
147 status = mmal_format_extradata_alloc(sys->input->format,
148 dec->fmt_in.i_extra);
149 if (status == MMAL_SUCCESS) {
150 memcpy(sys->input->format->extradata, dec->fmt_in.p_extra,
151 dec->fmt_in.i_extra);
152 sys->input->format->extradata_size = dec->fmt_in.i_extra;
153 } else {
154 msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)",
155 sys->input->name, status, mmal_status_to_string(status));
160 status = mmal_port_format_commit(sys->input);
161 if (status != MMAL_SUCCESS) {
162 msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
163 sys->input->name, status, mmal_status_to_string(status));
164 ret = VLC_EGENERIC;
165 goto out;
167 sys->input->buffer_size = sys->input->buffer_size_recommended;
168 sys->input->buffer_num = sys->input->buffer_num_recommended;
170 status = mmal_port_enable(sys->input, input_port_cb);
171 if (status != MMAL_SUCCESS) {
172 msg_Err(dec, "Failed to enable input port %s (status=%"PRIx32" %s)",
173 sys->input->name, status, mmal_status_to_string(status));
174 ret = VLC_EGENERIC;
175 goto out;
178 sys->output = sys->component->output[0];
179 sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
181 if (sys->opaque) {
182 extra_buffers.hdr.id = MMAL_PARAMETER_EXTRA_BUFFERS;
183 extra_buffers.hdr.size = sizeof(MMAL_PARAMETER_UINT32_T);
184 extra_buffers.value = NUM_EXTRA_BUFFERS;
185 status = mmal_port_parameter_set(sys->output, &extra_buffers.hdr);
186 if (status != MMAL_SUCCESS) {
187 msg_Err(dec, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)",
188 status, mmal_status_to_string(status));
189 ret = VLC_EGENERIC;
190 goto out;
193 msg_Dbg(dec, "Activate zero-copy for output port");
194 MMAL_PARAMETER_BOOLEAN_T zero_copy = {
195 { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) },
199 status = mmal_port_parameter_set(sys->output, &zero_copy.hdr);
200 if (status != MMAL_SUCCESS) {
201 msg_Err(dec, "Failed to set zero copy on port %s (status=%"PRIx32" %s)",
202 sys->output->name, status, mmal_status_to_string(status));
203 goto out;
207 status = mmal_port_enable(sys->output, output_port_cb);
208 if (status != MMAL_SUCCESS) {
209 msg_Err(dec, "Failed to enable output port %s (status=%"PRIx32" %s)",
210 sys->output->name, status, mmal_status_to_string(status));
211 ret = VLC_EGENERIC;
212 goto out;
215 status = mmal_component_enable(sys->component);
216 if (status != MMAL_SUCCESS) {
217 msg_Err(dec, "Failed to enable component %s (status=%"PRIx32" %s)",
218 sys->component->name, status, mmal_status_to_string(status));
219 ret = VLC_EGENERIC;
220 goto out;
223 sys->input_pool = mmal_pool_create(sys->input->buffer_num, 0);
224 sys->decoded_pictures = mmal_queue_create();
226 if (sys->opaque) {
227 dec->fmt_out.i_codec = VLC_CODEC_MMAL_OPAQUE;
228 dec->fmt_out.video.i_chroma = VLC_CODEC_MMAL_OPAQUE;
229 } else {
230 dec->fmt_out.i_codec = VLC_CODEC_I420;
231 dec->fmt_out.video.i_chroma = VLC_CODEC_I420;
234 dec->pf_decode = decode;
235 dec->pf_flush = flush_decoder;
237 vlc_sem_init(&sys->sem, 0);
239 out:
240 if (ret != VLC_SUCCESS)
241 CloseDecoder(dec);
243 return ret;
246 static void CloseDecoder(decoder_t *dec)
248 decoder_sys_t *sys = dec->p_sys;
249 MMAL_BUFFER_HEADER_T *buffer;
251 if (!sys)
252 return;
254 if (sys->component && sys->component->control->is_enabled)
255 mmal_port_disable(sys->component->control);
257 if (sys->input && sys->input->is_enabled)
258 mmal_port_disable(sys->input);
260 if (sys->output && sys->output->is_enabled)
261 mmal_port_disable(sys->output);
263 if (sys->component && sys->component->is_enabled)
264 mmal_component_disable(sys->component);
266 if (sys->input_pool)
267 mmal_pool_destroy(sys->input_pool);
269 if (sys->output_format)
270 mmal_format_free(sys->output_format);
272 /* Free pictures which are decoded but have not yet been sent
273 * out to the core */
274 while ((buffer = mmal_queue_get(sys->decoded_pictures))) {
275 picture_t *pic = (picture_t *)buffer->user_data;
276 picture_Release(pic);
278 if (sys->output_pool) {
279 buffer->user_data = NULL;
280 buffer->alloc_size = 0;
281 buffer->data = NULL;
282 mmal_buffer_header_release(buffer);
286 if (sys->decoded_pictures)
287 mmal_queue_destroy(sys->decoded_pictures);
289 if (sys->output_pool)
290 mmal_pool_destroy(sys->output_pool);
292 if (sys->component)
293 mmal_component_release(sys->component);
295 vlc_sem_destroy(&sys->sem);
296 free(sys);
298 bcm_host_deinit();
301 static int change_output_format(decoder_t *dec)
303 MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type;
304 decoder_sys_t *sys = dec->p_sys;
305 MMAL_STATUS_T status;
306 int pool_size;
307 int ret = 0;
309 if (atomic_load(&sys->started)) {
310 mmal_format_full_copy(sys->output->format, sys->output_format);
311 status = mmal_port_format_commit(sys->output);
312 if (status != MMAL_SUCCESS) {
313 msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)",
314 status, mmal_status_to_string(status));
315 ret = -1;
316 goto port_reset;
318 goto apply_fmt;
321 port_reset:
322 msg_Dbg(dec, "%s: Do full port reset", __func__);
323 status = mmal_port_disable(sys->output);
324 if (status != MMAL_SUCCESS) {
325 msg_Err(dec, "Failed to disable output port (status=%"PRIx32" %s)",
326 status, mmal_status_to_string(status));
327 ret = -1;
328 goto out;
331 mmal_format_full_copy(sys->output->format, sys->output_format);
332 status = mmal_port_format_commit(sys->output);
333 if (status != MMAL_SUCCESS) {
334 msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)",
335 status, mmal_status_to_string(status));
336 ret = -1;
337 goto out;
340 if (sys->opaque) {
341 sys->output->buffer_num = NUM_ACTUAL_OPAQUE_BUFFERS;
342 pool_size = NUM_DECODER_BUFFER_HEADERS;
343 } else {
344 sys->output->buffer_num = __MAX(sys->output->buffer_num_recommended,
345 MIN_NUM_BUFFERS_IN_TRANSIT);
346 pool_size = sys->output->buffer_num;
349 sys->output->buffer_size = sys->output->buffer_size_recommended;
351 status = mmal_port_enable(sys->output, output_port_cb);
352 if (status != MMAL_SUCCESS) {
353 msg_Err(dec, "Failed to enable output port (status=%"PRIx32" %s)",
354 status, mmal_status_to_string(status));
355 ret = -1;
356 goto out;
359 if (!atomic_load(&sys->started)) {
360 if (!sys->opaque) {
361 sys->output_pool = mmal_port_pool_create(sys->output, pool_size, 0);
362 msg_Dbg(dec, "Created output pool with %d pictures", sys->output_pool->headers_num);
365 atomic_store(&sys->started, true);
367 /* we need one picture from vout for each buffer header on the output
368 * port */
369 dec->i_extra_picture_buffers = pool_size;
371 /* remove what VLC core reserves as it is part of the pool_size
372 * already */
373 if (dec->fmt_in.i_codec == VLC_CODEC_H264)
374 dec->i_extra_picture_buffers -= 19;
375 else
376 dec->i_extra_picture_buffers -= 3;
378 msg_Dbg(dec, "Request %d extra pictures", dec->i_extra_picture_buffers);
381 apply_fmt:
382 dec->fmt_out.video.i_width = sys->output->format->es->video.width;
383 dec->fmt_out.video.i_height = sys->output->format->es->video.height;
384 dec->fmt_out.video.i_x_offset = sys->output->format->es->video.crop.x;
385 dec->fmt_out.video.i_y_offset = sys->output->format->es->video.crop.y;
386 dec->fmt_out.video.i_visible_width = sys->output->format->es->video.crop.width;
387 dec->fmt_out.video.i_visible_height = sys->output->format->es->video.crop.height;
388 dec->fmt_out.video.i_sar_num = sys->output->format->es->video.par.num;
389 dec->fmt_out.video.i_sar_den = sys->output->format->es->video.par.den;
390 dec->fmt_out.video.i_frame_rate = sys->output->format->es->video.frame_rate.num;
391 dec->fmt_out.video.i_frame_rate_base = sys->output->format->es->video.frame_rate.den;
393 /* Query interlaced type */
394 interlace_type.hdr.id = MMAL_PARAMETER_VIDEO_INTERLACE_TYPE;
395 interlace_type.hdr.size = sizeof(MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T);
396 status = mmal_port_parameter_get(sys->output, &interlace_type.hdr);
397 if (status != MMAL_SUCCESS) {
398 msg_Warn(dec, "Failed to query interlace type from decoder output port (status=%"PRIx32" %s)",
399 status, mmal_status_to_string(status));
400 } else {
401 sys->b_progressive = (interlace_type.eMode == MMAL_InterlaceProgressive);
402 sys->b_top_field_first = sys->b_progressive ? true :
403 (interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst);
404 msg_Dbg(dec, "Detected %s%s video (%d)",
405 sys->b_progressive ? "progressive" : "interlaced",
406 sys->b_progressive ? "" : (sys->b_top_field_first ? " tff" : " bff"),
407 interlace_type.eMode);
410 out:
411 mmal_format_free(sys->output_format);
412 sys->output_format = NULL;
414 return ret;
417 static int send_output_buffer(decoder_t *dec)
419 decoder_sys_t *sys = dec->p_sys;
420 MMAL_BUFFER_HEADER_T *buffer;
421 picture_sys_t *p_sys;
422 picture_t *picture = NULL;
423 MMAL_STATUS_T status;
424 unsigned buffer_size = 0;
425 int ret = 0;
427 if (!sys->output->is_enabled)
428 return VLC_EGENERIC;
430 /* If local output pool is allocated, use it - this is only the case for
431 * non-opaque modes */
432 if (sys->output_pool) {
433 buffer = mmal_queue_get(sys->output_pool->queue);
434 if (!buffer) {
435 msg_Warn(dec, "Failed to get new buffer");
436 return VLC_EGENERIC;
440 if (!decoder_UpdateVideoFormat(dec))
441 picture = decoder_NewPicture(dec);
442 if (!picture) {
443 msg_Warn(dec, "Failed to get new picture");
444 ret = -1;
445 goto err;
448 p_sys = picture->p_sys;
449 for (int i = 0; i < picture->i_planes; i++)
450 buffer_size += picture->p[i].i_lines * picture->p[i].i_pitch;
452 if (sys->output_pool) {
453 mmal_buffer_header_reset(buffer);
454 buffer->alloc_size = sys->output->buffer_size;
455 if (buffer_size < sys->output->buffer_size) {
456 msg_Err(dec, "Retrieved picture with too small data block (%d < %d)",
457 buffer_size, sys->output->buffer_size);
458 ret = VLC_EGENERIC;
459 goto err;
462 if (!sys->opaque)
463 buffer->data = picture->p[0].p_pixels;
464 } else {
465 buffer = p_sys->buffer;
466 if (!buffer) {
467 msg_Warn(dec, "Picture has no buffer attached");
468 picture_Release(picture);
469 return VLC_EGENERIC;
471 buffer->data = p_sys->buffer->data;
473 buffer->user_data = picture;
474 buffer->cmd = 0;
476 status = mmal_port_send_buffer(sys->output, buffer);
477 if (status != MMAL_SUCCESS) {
478 msg_Err(dec, "Failed to send buffer to output port (status=%"PRIx32" %s)",
479 status, mmal_status_to_string(status));
480 ret = -1;
481 goto err;
483 atomic_fetch_add(&sys->output_in_transit, 1);
485 return ret;
487 err:
488 if (picture)
489 picture_Release(picture);
490 if (sys->output_pool && buffer) {
491 buffer->data = NULL;
492 mmal_buffer_header_release(buffer);
494 return ret;
497 static void fill_output_port(decoder_t *dec)
499 decoder_sys_t *sys = dec->p_sys;
501 unsigned max_buffers_in_transit = 0;
502 int buffers_available = 0;
503 int buffers_to_send = 0;
504 int i;
506 if (sys->output_pool) {
507 max_buffers_in_transit = __MAX(sys->output_pool->headers_num,
508 MIN_NUM_BUFFERS_IN_TRANSIT);
509 buffers_available = mmal_queue_length(sys->output_pool->queue);
510 } else {
511 max_buffers_in_transit = __MAX(sys->output->buffer_num, MIN_NUM_BUFFERS_IN_TRANSIT);
512 buffers_available = NUM_DECODER_BUFFER_HEADERS - atomic_load(&sys->output_in_transit) -
513 mmal_queue_length(sys->decoded_pictures);
515 buffers_to_send = max_buffers_in_transit - atomic_load(&sys->output_in_transit);
517 if (buffers_to_send > buffers_available)
518 buffers_to_send = buffers_available;
520 #ifndef NDEBUG
521 msg_Dbg(dec, "Send %d buffers to output port (available: %d, "
522 "in_transit: %d, decoded: %d, buffer_num: %d)",
523 buffers_to_send, buffers_available,
524 atomic_load(&sys->output_in_transit),
525 mmal_queue_length(sys->decoded_pictures),
526 sys->output->buffer_num);
527 #endif
528 for (i = 0; i < buffers_to_send; ++i)
529 if (send_output_buffer(dec) < 0)
530 break;
533 static void flush_decoder(decoder_t *dec)
535 decoder_sys_t *sys = dec->p_sys;
536 MMAL_BUFFER_HEADER_T *buffer;
537 MMAL_STATUS_T status;
539 msg_Dbg(dec, "Flushing decoder ports...");
540 mmal_port_disable(sys->output);
541 mmal_port_disable(sys->input);
542 mmal_port_flush(sys->output);
543 mmal_port_flush(sys->input);
545 /* Reload extradata if available */
546 if (dec->fmt_in.i_codec == VLC_CODEC_H264) {
547 if (dec->fmt_in.i_extra > 0) {
548 status = mmal_format_extradata_alloc(sys->input->format,
549 dec->fmt_in.i_extra);
550 if (status == MMAL_SUCCESS) {
551 memcpy(sys->input->format->extradata, dec->fmt_in.p_extra,
552 dec->fmt_in.i_extra);
553 sys->input->format->extradata_size = dec->fmt_in.i_extra;
554 } else {
555 msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)",
556 sys->input->name, status, mmal_status_to_string(status));
561 status = mmal_port_format_commit(sys->input);
562 if (status != MMAL_SUCCESS) {
563 msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
564 sys->input->name, status, mmal_status_to_string(status));
567 mmal_port_enable(sys->output, output_port_cb);
568 mmal_port_enable(sys->input, input_port_cb);
570 while (atomic_load(&sys->output_in_transit))
571 vlc_sem_wait(&sys->sem);
573 /* Free pictures which are decoded but have not yet been sent
574 * out to the core */
575 while ((buffer = mmal_queue_get(sys->decoded_pictures))) {
576 picture_t *pic = (picture_t *)buffer->user_data;
577 picture_Release(pic);
579 if (sys->output_pool) {
580 buffer->user_data = NULL;
581 buffer->alloc_size = 0;
582 buffer->data = NULL;
583 mmal_buffer_header_release(buffer);
586 msg_Dbg(dec, "Ports flushed, returning to normal operation");
589 static int decode(decoder_t *dec, block_t *block)
591 decoder_sys_t *sys = dec->p_sys;
592 MMAL_BUFFER_HEADER_T *buffer;
593 bool need_flush = false;
594 uint32_t len;
595 uint32_t flags = 0;
596 MMAL_STATUS_T status;
599 * Configure output port if necessary
601 if (sys->output_format) {
602 if (change_output_format(dec) < 0)
603 msg_Err(dec, "Failed to change output port format");
606 if (!block)
607 goto out;
610 * Check whether full flush is required
612 if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) {
613 flush_decoder(dec);
614 block_Release(block);
615 return VLCDEC_SUCCESS;
619 * Send output buffers
621 picture_t *ret = NULL;
622 if (atomic_load(&sys->started)) {
623 buffer = mmal_queue_get(sys->decoded_pictures);
624 if (buffer) {
625 ret = (picture_t *)buffer->user_data;
626 ret->date = buffer->pts;
627 ret->b_progressive = sys->b_progressive;
628 ret->b_top_field_first = sys->b_top_field_first;
630 if (sys->output_pool) {
631 buffer->data = NULL;
632 mmal_buffer_header_reset(buffer);
633 mmal_buffer_header_release(buffer);
637 fill_output_port(dec);
639 if (ret)
640 decoder_QueueVideo(dec, ret);
643 * Process input
646 if (block->i_flags & BLOCK_FLAG_CORRUPTED)
647 flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;
649 while (block && block->i_buffer > 0) {
650 buffer = mmal_queue_timedwait(sys->input_pool->queue, 2);
651 if (!buffer) {
652 msg_Err(dec, "Failed to retrieve buffer header for input data");
653 need_flush = true;
654 break;
656 mmal_buffer_header_reset(buffer);
657 buffer->cmd = 0;
658 buffer->pts = block->i_pts != 0 ? block->i_pts : block->i_dts;
659 buffer->dts = block->i_dts;
660 buffer->alloc_size = sys->input->buffer_size;
662 len = block->i_buffer;
663 if (len > buffer->alloc_size)
664 len = buffer->alloc_size;
666 buffer->data = block->p_buffer;
667 block->p_buffer += len;
668 block->i_buffer -= len;
669 buffer->length = len;
670 if (block->i_buffer == 0) {
671 buffer->user_data = block;
672 block = NULL;
674 buffer->flags = flags;
676 status = mmal_port_send_buffer(sys->input, buffer);
677 if (status != MMAL_SUCCESS) {
678 msg_Err(dec, "Failed to send buffer to input port (status=%"PRIx32" %s)",
679 status, mmal_status_to_string(status));
680 break;
682 atomic_fetch_add(&sys->input_in_transit, 1);
685 out:
686 if (need_flush)
687 flush_decoder(dec);
689 return VLCDEC_SUCCESS;
692 static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
694 decoder_t *dec = (decoder_t *)port->userdata;
695 MMAL_STATUS_T status;
697 if (buffer->cmd == MMAL_EVENT_ERROR) {
698 status = *(uint32_t *)buffer->data;
699 msg_Err(dec, "MMAL error %"PRIx32" \"%s\"", status,
700 mmal_status_to_string(status));
703 mmal_buffer_header_release(buffer);
706 static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
708 block_t *block = (block_t *)buffer->user_data;
709 decoder_t *dec = (decoder_t *)port->userdata;
710 decoder_sys_t *sys = dec->p_sys;
711 buffer->user_data = NULL;
713 mmal_buffer_header_release(buffer);
714 if (block)
715 block_Release(block);
716 atomic_fetch_sub(&sys->input_in_transit, 1);
717 vlc_sem_post(&sys->sem);
720 static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
722 decoder_t *dec = (decoder_t *)port->userdata;
723 decoder_sys_t *sys = dec->p_sys;
724 picture_t *picture;
725 MMAL_EVENT_FORMAT_CHANGED_T *fmt;
726 MMAL_ES_FORMAT_T *format;
728 if (buffer->cmd == 0) {
729 if (buffer->length > 0) {
730 mmal_queue_put(sys->decoded_pictures, buffer);
731 } else {
732 picture = (picture_t *)buffer->user_data;
733 picture_Release(picture);
734 if (sys->output_pool) {
735 buffer->user_data = NULL;
736 buffer->alloc_size = 0;
737 buffer->data = NULL;
738 mmal_buffer_header_release(buffer);
741 atomic_fetch_sub(&sys->output_in_transit, 1);
742 vlc_sem_post(&sys->sem);
743 } else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) {
744 fmt = mmal_event_format_changed_get(buffer);
746 format = mmal_format_alloc();
747 mmal_format_full_copy(format, fmt->format);
749 if (sys->opaque)
750 format->encoding = MMAL_ENCODING_OPAQUE;
752 sys->output_format = format;
754 mmal_buffer_header_release(buffer);
755 } else {
756 mmal_buffer_header_release(buffer);