1 /*****************************************************************************
2 * mmal.c: MMAL-based decoder plugin for Raspberry Pi
3 *****************************************************************************
4 * Copyright © 2014 jusst technologies GmbH
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 *****************************************************************************/
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>
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
);
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
)
66 struct decoder_sys_t
{
68 MMAL_COMPONENT_T
*component
;
70 MMAL_POOL_T
*input_pool
;
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
;
77 bool b_top_field_first
;
81 int output_in_transit
;
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
);
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
;
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
)
111 sys
= calloc(1, sizeof(decoder_sys_t
));
118 sys
->opaque
= var_InheritBool(dec
, MMAL_OPAQUE_NAME
);
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
));
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
));
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
;
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
;
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
));
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
));
178 sys
->output
= sys
->component
->output
[0];
179 sys
->output
->userdata
= (struct MMAL_PORT_USERDATA_T
*)dec
;
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
));
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
));
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
));
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
));
223 sys
->input_pool
= mmal_pool_create(sys
->input
->buffer_num
, 0);
224 sys
->decoded_pictures
= mmal_queue_create();
227 dec
->fmt_out
.i_codec
= VLC_CODEC_MMAL_OPAQUE
;
228 dec
->fmt_out
.video
.i_chroma
= VLC_CODEC_MMAL_OPAQUE
;
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);
240 if (ret
!= VLC_SUCCESS
)
246 static void CloseDecoder(decoder_t
*dec
)
248 decoder_sys_t
*sys
= dec
->p_sys
;
249 MMAL_BUFFER_HEADER_T
*buffer
;
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
);
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
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;
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
);
293 mmal_component_release(sys
->component
);
295 vlc_sem_destroy(&sys
->sem
);
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
;
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
));
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
));
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
));
341 sys
->output
->buffer_num
= NUM_ACTUAL_OPAQUE_BUFFERS
;
342 pool_size
= NUM_DECODER_BUFFER_HEADERS
;
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
));
359 if (!atomic_load(&sys
->started
)) {
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
369 dec
->i_extra_picture_buffers
= pool_size
;
371 /* remove what VLC core reserves as it is part of the pool_size
373 if (dec
->fmt_in
.i_codec
== VLC_CODEC_H264
)
374 dec
->i_extra_picture_buffers
-= 19;
376 dec
->i_extra_picture_buffers
-= 3;
378 msg_Dbg(dec
, "Request %d extra pictures", dec
->i_extra_picture_buffers
);
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
));
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
);
411 mmal_format_free(sys
->output_format
);
412 sys
->output_format
= NULL
;
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;
427 if (!sys
->output
->is_enabled
)
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
);
435 msg_Warn(dec
, "Failed to get new buffer");
440 if (!decoder_UpdateVideoFormat(dec
))
441 picture
= decoder_NewPicture(dec
);
443 msg_Warn(dec
, "Failed to get new picture");
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
);
463 buffer
->data
= picture
->p
[0].p_pixels
;
465 buffer
= p_sys
->buffer
;
467 msg_Warn(dec
, "Picture has no buffer attached");
468 picture_Release(picture
);
471 buffer
->data
= p_sys
->buffer
->data
;
473 buffer
->user_data
= picture
;
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
));
483 atomic_fetch_add(&sys
->output_in_transit
, 1);
489 picture_Release(picture
);
490 if (sys
->output_pool
&& buffer
) {
492 mmal_buffer_header_release(buffer
);
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;
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
);
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
;
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
);
528 for (i
= 0; i
< buffers_to_send
; ++i
)
529 if (send_output_buffer(dec
) < 0)
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
;
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
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;
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;
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");
610 * Check whether full flush is required
612 if (block
&& block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
) {
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
);
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
) {
632 mmal_buffer_header_reset(buffer
);
633 mmal_buffer_header_release(buffer
);
637 fill_output_port(dec
);
640 decoder_QueueVideo(dec
, ret
);
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);
652 msg_Err(dec
, "Failed to retrieve buffer header for input data");
656 mmal_buffer_header_reset(buffer
);
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
;
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
));
682 atomic_fetch_add(&sys
->input_in_transit
, 1);
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
);
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
;
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
);
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;
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
);
750 format
->encoding
= MMAL_ENCODING_OPAQUE
;
752 sys
->output_format
= format
;
754 mmal_buffer_header_release(buffer
);
756 mmal_buffer_header_release(buffer
);