1 /*****************************************************************************
2 * mmal.c: MMAL-based decoder plugin for Raspberry Pi
3 *****************************************************************************
4 * Copyright © 2014 jusst technologies GmbH
5 * $Id: 99ff21ca701e6c600c9d61dcebe94a814d16560f $
6 *
7 * Authors: Dennis Hamester <dennis.hamester@gmail.com>
8 * Julian Scheel <julian@jusst.de>
9 *
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.
14 *
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.
19 *
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 *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
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>
34
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>
39
40 #include "mmal_picture.h"
41
42 /*
43 * This seems to be a bit high, but reducing it causes instabilities
44 */
45 #define NUM_EXTRA_BUFFERS 5
46 #define NUM_DECODER_BUFFER_HEADERS 30
47
48 #define MIN_NUM_BUFFERS_IN_TRANSIT 2
49
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.")
53
54 static int OpenDecoder(decoder_t *dec);
55 static void CloseDecoder(decoder_t *dec);
56
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()
65
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 vlc_sem_t sem;
75
76 bool b_top_field_first;
77 bool b_progressive;
78
79 /* statistics */
80 int output_in_transit;
81 int input_in_transit;
82 atomic_bool started;
83 };
84
85 /* Utilities */
86 static int change_output_format(decoder_t *dec);
87 static int send_output_buffer(decoder_t *dec);
88 static void fill_output_port(decoder_t *dec);
89
90 /* VLC decoder callback */
91 static int decode(decoder_t *dec, block_t *block);
92 static void flush_decoder(decoder_t *dec);
93
94 /* MMAL callbacks */
95 static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
96 static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
97 static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
98
OpenDecoder(decoder_t * dec)99 static int OpenDecoder(decoder_t *dec)
100 {
101 int ret = VLC_SUCCESS;
102 decoder_sys_t *sys;
103 MMAL_PARAMETER_UINT32_T extra_buffers;
104 MMAL_STATUS_T status;
105
106 if (dec->fmt_in.i_codec != VLC_CODEC_MPGV &&
107 dec->fmt_in.i_codec != VLC_CODEC_H264)
108 return VLC_EGENERIC;
109
110 sys = calloc(1, sizeof(decoder_sys_t));
111 if (!sys) {
112 ret = VLC_ENOMEM;
113 goto out;
114 }
115 dec->p_sys = sys;
116
117 sys->opaque = var_InheritBool(dec, MMAL_OPAQUE_NAME);
118 bcm_host_init();
119
120 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &sys->component);
121 if (status != MMAL_SUCCESS) {
122 msg_Err(dec, "Failed to create MMAL component %s (status=%"PRIx32" %s)",
123 MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status));
124 ret = VLC_EGENERIC;
125 goto out;
126 }
127
128 sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
129 status = mmal_port_enable(sys->component->control, control_port_cb);
130 if (status != MMAL_SUCCESS) {
131 msg_Err(dec, "Failed to enable control port %s (status=%"PRIx32" %s)",
132 sys->component->control->name, status, mmal_status_to_string(status));
133 ret = VLC_EGENERIC;
134 goto out;
135 }
136
137 sys->input = sys->component->input[0];
138 sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
139 if (dec->fmt_in.i_codec == VLC_CODEC_MPGV)
140 sys->input->format->encoding = MMAL_ENCODING_MP2V;
141 else
142 sys->input->format->encoding = MMAL_ENCODING_H264;
143
144 if (dec->fmt_in.i_codec == VLC_CODEC_H264) {
145 if (dec->fmt_in.i_extra > 0) {
146 status = mmal_format_extradata_alloc(sys->input->format,
147 dec->fmt_in.i_extra);
148 if (status == MMAL_SUCCESS) {
149 memcpy(sys->input->format->extradata, dec->fmt_in.p_extra,
150 dec->fmt_in.i_extra);
151 sys->input->format->extradata_size = dec->fmt_in.i_extra;
152 } else {
153 msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)",
154 sys->input->name, status, mmal_status_to_string(status));
155 }
156 }
157 }
158
159 status = mmal_port_format_commit(sys->input);
160 if (status != MMAL_SUCCESS) {
161 msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
162 sys->input->name, status, mmal_status_to_string(status));
163 ret = VLC_EGENERIC;
164 goto out;
165 }
166 sys->input->buffer_size = sys->input->buffer_size_recommended;
167 sys->input->buffer_num = sys->input->buffer_num_recommended;
168
169 status = mmal_port_enable(sys->input, input_port_cb);
170 if (status != MMAL_SUCCESS) {
171 msg_Err(dec, "Failed to enable input port %s (status=%"PRIx32" %s)",
172 sys->input->name, status, mmal_status_to_string(status));
173 ret = VLC_EGENERIC;
174 goto out;
175 }
176
177 sys->output = sys->component->output[0];
178 sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
179
180 if (sys->opaque) {
181 extra_buffers.hdr.id = MMAL_PARAMETER_EXTRA_BUFFERS;
182 extra_buffers.hdr.size = sizeof(MMAL_PARAMETER_UINT32_T);
183 extra_buffers.value = NUM_EXTRA_BUFFERS;
184 status = mmal_port_parameter_set(sys->output, &extra_buffers.hdr);
185 if (status != MMAL_SUCCESS) {
186 msg_Err(dec, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)",
187 status, mmal_status_to_string(status));
188 ret = VLC_EGENERIC;
189 goto out;
190 }
191
192 msg_Dbg(dec, "Activate zero-copy for output port");
193 MMAL_PARAMETER_BOOLEAN_T zero_copy = {
194 { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) },
195 1
196 };
197
198 status = mmal_port_parameter_set(sys->output, &zero_copy.hdr);
199 if (status != MMAL_SUCCESS) {
200 msg_Err(dec, "Failed to set zero copy on port %s (status=%"PRIx32" %s)",
201 sys->output->name, status, mmal_status_to_string(status));
202 goto out;
203 }
204 }
205
206 status = mmal_port_enable(sys->output, output_port_cb);
207 if (status != MMAL_SUCCESS) {
208 msg_Err(dec, "Failed to enable output port %s (status=%"PRIx32" %s)",
209 sys->output->name, status, mmal_status_to_string(status));
210 ret = VLC_EGENERIC;
211 goto out;
212 }
213
214 status = mmal_component_enable(sys->component);
215 if (status != MMAL_SUCCESS) {
216 msg_Err(dec, "Failed to enable component %s (status=%"PRIx32" %s)",
217 sys->component->name, status, mmal_status_to_string(status));
218 ret = VLC_EGENERIC;
219 goto out;
220 }
221
222 sys->input_pool = mmal_pool_create(sys->input->buffer_num, 0);
223
224 if (sys->opaque) {
225 dec->fmt_out.i_codec = VLC_CODEC_MMAL_OPAQUE;
226 dec->fmt_out.video.i_chroma = VLC_CODEC_MMAL_OPAQUE;
227 } else {
228 dec->fmt_out.i_codec = VLC_CODEC_I420;
229 dec->fmt_out.video.i_chroma = VLC_CODEC_I420;
230 }
231
232 dec->pf_decode = decode;
233 dec->pf_flush = flush_decoder;
234
235 vlc_sem_init(&sys->sem, 0);
236
237 out:
238 if (ret != VLC_SUCCESS)
239 CloseDecoder(dec);
240
241 return ret;
242 }
243
CloseDecoder(decoder_t * dec)244 static void CloseDecoder(decoder_t *dec)
245 {
246 decoder_sys_t *sys = dec->p_sys;
247 MMAL_BUFFER_HEADER_T *buffer;
248
249 if (!sys)
250 return;
251
252 if (sys->component && sys->component->control->is_enabled)
253 mmal_port_disable(sys->component->control);
254
255 if (sys->input && sys->input->is_enabled)
256 mmal_port_disable(sys->input);
257
258 if (sys->output && sys->output->is_enabled)
259 mmal_port_disable(sys->output);
260
261 if (sys->component && sys->component->is_enabled)
262 mmal_component_disable(sys->component);
263
264 if (sys->input_pool)
265 mmal_pool_destroy(sys->input_pool);
266
267 if (sys->output_format)
268 mmal_format_free(sys->output_format);
269
270 if (sys->output_pool)
271 mmal_pool_destroy(sys->output_pool);
272
273 if (sys->component)
274 mmal_component_release(sys->component);
275
276 vlc_sem_destroy(&sys->sem);
277 free(sys);
278
279 bcm_host_deinit();
280 }
281
change_output_format(decoder_t * dec)282 static int change_output_format(decoder_t *dec)
283 {
284 MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type;
285 decoder_sys_t *sys = dec->p_sys;
286 MMAL_STATUS_T status;
287 int pool_size;
288 int ret = 0;
289
290 if (atomic_load(&sys->started)) {
291 mmal_format_full_copy(sys->output->format, sys->output_format);
292 status = mmal_port_format_commit(sys->output);
293 if (status != MMAL_SUCCESS) {
294 msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)",
295 status, mmal_status_to_string(status));
296 ret = -1;
297 goto port_reset;
298 }
299 goto apply_fmt;
300 }
301
302 port_reset:
303 msg_Dbg(dec, "%s: Do full port reset", __func__);
304 status = mmal_port_disable(sys->output);
305 if (status != MMAL_SUCCESS) {
306 msg_Err(dec, "Failed to disable output port (status=%"PRIx32" %s)",
307 status, mmal_status_to_string(status));
308 ret = -1;
309 goto out;
310 }
311
312 mmal_format_full_copy(sys->output->format, sys->output_format);
313 status = mmal_port_format_commit(sys->output);
314 if (status != MMAL_SUCCESS) {
315 msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)",
316 status, mmal_status_to_string(status));
317 ret = -1;
318 goto out;
319 }
320
321 if (sys->opaque) {
322 sys->output->buffer_num = NUM_DECODER_BUFFER_HEADERS;
323 pool_size = NUM_DECODER_BUFFER_HEADERS;
324 } else {
325 sys->output->buffer_num = __MAX(sys->output->buffer_num_recommended,
326 MIN_NUM_BUFFERS_IN_TRANSIT);
327 pool_size = sys->output->buffer_num;
328 }
329
330 sys->output->buffer_size = sys->output->buffer_size_recommended;
331
332 status = mmal_port_enable(sys->output, output_port_cb);
333 if (status != MMAL_SUCCESS) {
334 msg_Err(dec, "Failed to enable output port (status=%"PRIx32" %s)",
335 status, mmal_status_to_string(status));
336 ret = -1;
337 goto out;
338 }
339
340 if (!atomic_load(&sys->started)) {
341 if (!sys->opaque) {
342 sys->output_pool = mmal_port_pool_create(sys->output, pool_size, 0);
343 msg_Dbg(dec, "Created output pool with %d pictures", sys->output_pool->headers_num);
344 }
345
346 atomic_store(&sys->started, true);
347
348 /* we need one picture from vout for each buffer header on the output
349 * port */
350 dec->i_extra_picture_buffers = pool_size;
351
352 /* remove what VLC core reserves as it is part of the pool_size
353 * already */
354 if (dec->fmt_in.i_codec == VLC_CODEC_H264)
355 dec->i_extra_picture_buffers -= 19;
356 else
357 dec->i_extra_picture_buffers -= 3;
358
359 msg_Dbg(dec, "Request %d extra pictures", dec->i_extra_picture_buffers);
360 }
361
362 apply_fmt:
363 dec->fmt_out.video.i_width = sys->output->format->es->video.width;
364 dec->fmt_out.video.i_height = sys->output->format->es->video.height;
365 dec->fmt_out.video.i_x_offset = sys->output->format->es->video.crop.x;
366 dec->fmt_out.video.i_y_offset = sys->output->format->es->video.crop.y;
367 dec->fmt_out.video.i_visible_width = sys->output->format->es->video.crop.width;
368 dec->fmt_out.video.i_visible_height = sys->output->format->es->video.crop.height;
369 dec->fmt_out.video.i_sar_num = sys->output->format->es->video.par.num;
370 dec->fmt_out.video.i_sar_den = sys->output->format->es->video.par.den;
371 dec->fmt_out.video.i_frame_rate = sys->output->format->es->video.frame_rate.num;
372 dec->fmt_out.video.i_frame_rate_base = sys->output->format->es->video.frame_rate.den;
373
374 /* Query interlaced type */
375 interlace_type.hdr.id = MMAL_PARAMETER_VIDEO_INTERLACE_TYPE;
376 interlace_type.hdr.size = sizeof(MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T);
377 status = mmal_port_parameter_get(sys->output, &interlace_type.hdr);
378 if (status != MMAL_SUCCESS) {
379 msg_Warn(dec, "Failed to query interlace type from decoder output port (status=%"PRIx32" %s)",
380 status, mmal_status_to_string(status));
381 } else {
382 sys->b_progressive = (interlace_type.eMode == MMAL_InterlaceProgressive);
383 sys->b_top_field_first = sys->b_progressive ? true :
384 (interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst);
385 msg_Dbg(dec, "Detected %s%s video (%d)",
386 sys->b_progressive ? "progressive" : "interlaced",
387 sys->b_progressive ? "" : (sys->b_top_field_first ? " tff" : " bff"),
388 interlace_type.eMode);
389 }
390
391 out:
392 mmal_format_free(sys->output_format);
393 sys->output_format = NULL;
394
395 return ret;
396 }
397
send_output_buffer(decoder_t * dec)398 static int send_output_buffer(decoder_t *dec)
399 {
400 decoder_sys_t *sys = dec->p_sys;
401 MMAL_BUFFER_HEADER_T *buffer;
402 picture_sys_t *p_sys;
403 picture_t *picture = NULL;
404 MMAL_STATUS_T status;
405 unsigned buffer_size = 0;
406 int ret = 0;
407
408 if (!sys->output->is_enabled)
409 return VLC_EGENERIC;
410
411 /* If local output pool is allocated, use it - this is only the case for
412 * non-opaque modes */
413 if (sys->output_pool) {
414 buffer = mmal_queue_get(sys->output_pool->queue);
415 if (!buffer) {
416 msg_Warn(dec, "Failed to get new buffer");
417 return VLC_EGENERIC;
418 }
419 }
420
421 if (!decoder_UpdateVideoFormat(dec))
422 picture = decoder_NewPicture(dec);
423 if (!picture) {
424 msg_Warn(dec, "Failed to get new picture");
425 ret = -1;
426 goto err;
427 }
428
429 p_sys = picture->p_sys;
430 for (int i = 0; i < picture->i_planes; i++)
431 buffer_size += picture->p[i].i_lines * picture->p[i].i_pitch;
432
433 if (sys->output_pool) {
434 mmal_buffer_header_reset(buffer);
435 buffer->alloc_size = sys->output->buffer_size;
436 if (buffer_size < sys->output->buffer_size) {
437 msg_Err(dec, "Retrieved picture with too small data block (%d < %d)",
438 buffer_size, sys->output->buffer_size);
439 ret = VLC_EGENERIC;
440 goto err;
441 }
442
443 if (!sys->opaque)
444 buffer->data = picture->p[0].p_pixels;
445 } else {
446 buffer = p_sys->buffer;
447 if (!buffer) {
448 msg_Warn(dec, "Picture has no buffer attached");
449 picture_Release(picture);
450 return VLC_EGENERIC;
451 }
452 buffer->data = p_sys->buffer->data;
453 }
454 buffer->user_data = picture;
455 buffer->cmd = 0;
456
457 status = mmal_port_send_buffer(sys->output, buffer);
458 if (status != MMAL_SUCCESS) {
459 msg_Err(dec, "Failed to send buffer to output port (status=%"PRIx32" %s)",
460 status, mmal_status_to_string(status));
461 ret = -1;
462 goto err;
463 }
464 atomic_fetch_add(&sys->output_in_transit, 1);
465
466 return ret;
467
468 err:
469 if (picture)
470 picture_Release(picture);
471 if (sys->output_pool && buffer) {
472 buffer->data = NULL;
473 mmal_buffer_header_release(buffer);
474 }
475 return ret;
476 }
477
fill_output_port(decoder_t * dec)478 static void fill_output_port(decoder_t *dec)
479 {
480 decoder_sys_t *sys = dec->p_sys;
481
482 unsigned max_buffers_in_transit = 0;
483 int buffers_available = 0;
484 int buffers_to_send = 0;
485 int i;
486
487 if (sys->output_pool) {
488 max_buffers_in_transit = __MAX(sys->output_pool->headers_num,
489 MIN_NUM_BUFFERS_IN_TRANSIT);
490 buffers_available = mmal_queue_length(sys->output_pool->queue);
491 } else {
492 max_buffers_in_transit = NUM_DECODER_BUFFER_HEADERS;
493 buffers_available = NUM_DECODER_BUFFER_HEADERS - atomic_load(&sys->output_in_transit);
494 }
495 buffers_to_send = max_buffers_in_transit - atomic_load(&sys->output_in_transit);
496
497 if (buffers_to_send > buffers_available)
498 buffers_to_send = buffers_available;
499
500 #ifndef NDEBUG
501 msg_Dbg(dec, "Send %d buffers to output port (available: %d, "
502 "in_transit: %d, buffer_num: %d)",
503 buffers_to_send, buffers_available,
504 atomic_load(&sys->output_in_transit),
505 sys->output->buffer_num);
506 #endif
507 for (i = 0; i < buffers_to_send; ++i)
508 if (send_output_buffer(dec) < 0)
509 break;
510 }
511
flush_decoder(decoder_t * dec)512 static void flush_decoder(decoder_t *dec)
513 {
514 decoder_sys_t *sys = dec->p_sys;
515 MMAL_BUFFER_HEADER_T *buffer;
516 MMAL_STATUS_T status;
517
518 msg_Dbg(dec, "Flushing decoder ports...");
519 mmal_port_flush(sys->output);
520 mmal_port_flush(sys->input);
521
522 while (atomic_load(&sys->output_in_transit) ||
523 atomic_load(&sys->input_in_transit))
524 vlc_sem_wait(&sys->sem);
525 }
526
decode(decoder_t * dec,block_t * block)527 static int decode(decoder_t *dec, block_t *block)
528 {
529 decoder_sys_t *sys = dec->p_sys;
530 MMAL_BUFFER_HEADER_T *buffer;
531 bool need_flush = false;
532 uint32_t len;
533 uint32_t flags = 0;
534 MMAL_STATUS_T status;
535
536 /*
537 * Configure output port if necessary
538 */
539 if (sys->output_format) {
540 if (change_output_format(dec) < 0)
541 msg_Err(dec, "Failed to change output port format");
542 }
543
544 if (!block)
545 goto out;
546
547 /*
548 * Check whether full flush is required
549 */
550 if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) {
551 flush_decoder(dec);
552 block_Release(block);
553 return VLCDEC_SUCCESS;
554 }
555
556 if (atomic_load(&sys->started))
557 fill_output_port(dec);
558
559 /*
560 * Process input
561 */
562
563 if (block->i_flags & BLOCK_FLAG_CORRUPTED)
564 flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;
565
566 while (block && block->i_buffer > 0) {
567 buffer = mmal_queue_timedwait(sys->input_pool->queue, 100);
568 if (!buffer) {
569 msg_Err(dec, "Failed to retrieve buffer header for input data");
570 need_flush = true;
571 break;
572 }
573 mmal_buffer_header_reset(buffer);
574 buffer->cmd = 0;
575 buffer->pts = block->i_pts != 0 ? block->i_pts : block->i_dts;
576 buffer->dts = block->i_dts;
577 buffer->alloc_size = sys->input->buffer_size;
578
579 len = block->i_buffer;
580 if (len > buffer->alloc_size)
581 len = buffer->alloc_size;
582
583 buffer->data = block->p_buffer;
584 block->p_buffer += len;
585 block->i_buffer -= len;
586 buffer->length = len;
587 if (block->i_buffer == 0) {
588 buffer->user_data = block;
589 block = NULL;
590 }
591 buffer->flags = flags;
592
593 status = mmal_port_send_buffer(sys->input, buffer);
594 if (status != MMAL_SUCCESS) {
595 msg_Err(dec, "Failed to send buffer to input port (status=%"PRIx32" %s)",
596 status, mmal_status_to_string(status));
597 break;
598 }
599 atomic_fetch_add(&sys->input_in_transit, 1);
600 }
601
602 out:
603 if (need_flush)
604 flush_decoder(dec);
605
606 return VLCDEC_SUCCESS;
607 }
608
control_port_cb(MMAL_PORT_T * port,MMAL_BUFFER_HEADER_T * buffer)609 static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
610 {
611 decoder_t *dec = (decoder_t *)port->userdata;
612 MMAL_STATUS_T status;
613
614 if (buffer->cmd == MMAL_EVENT_ERROR) {
615 status = *(uint32_t *)buffer->data;
616 msg_Err(dec, "MMAL error %"PRIx32" \"%s\"", status,
617 mmal_status_to_string(status));
618 }
619
620 mmal_buffer_header_release(buffer);
621 }
622
input_port_cb(MMAL_PORT_T * port,MMAL_BUFFER_HEADER_T * buffer)623 static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
624 {
625 block_t *block = (block_t *)buffer->user_data;
626 decoder_t *dec = (decoder_t *)port->userdata;
627 decoder_sys_t *sys = dec->p_sys;
628 buffer->user_data = NULL;
629
630 mmal_buffer_header_release(buffer);
631 if (block)
632 block_Release(block);
633 atomic_fetch_sub(&sys->input_in_transit, 1);
634 vlc_sem_post(&sys->sem);
635 }
636
output_port_cb(MMAL_PORT_T * port,MMAL_BUFFER_HEADER_T * buffer)637 static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
638 {
639 decoder_t *dec = (decoder_t *)port->userdata;
640 decoder_sys_t *sys = dec->p_sys;
641 picture_t *picture;
642 MMAL_EVENT_FORMAT_CHANGED_T *fmt;
643 MMAL_ES_FORMAT_T *format;
644
645 if (buffer->cmd == 0) {
646 picture = (picture_t *)buffer->user_data;
647 if (buffer->length > 0) {
648 picture->date = buffer->pts;
649 picture->b_progressive = sys->b_progressive;
650 picture->b_top_field_first = sys->b_top_field_first;
651 decoder_QueueVideo(dec, picture);
652 } else {
653 picture_Release(picture);
654 if (sys->output_pool) {
655 buffer->user_data = NULL;
656 buffer->alloc_size = 0;
657 buffer->data = NULL;
658 mmal_buffer_header_release(buffer);
659 }
660 }
661 atomic_fetch_sub(&sys->output_in_transit, 1);
662 vlc_sem_post(&sys->sem);
663 } else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) {
664 fmt = mmal_event_format_changed_get(buffer);
665
666 format = mmal_format_alloc();
667 mmal_format_full_copy(format, fmt->format);
668
669 if (sys->opaque)
670 format->encoding = MMAL_ENCODING_OPAQUE;
671
672 sys->output_format = format;
673
674 mmal_buffer_header_release(buffer);
675 } else {
676 mmal_buffer_header_release(buffer);
677 }
678 }
679