FFmpeg
Loading...
Searching...
No Matches
mmaldec.c
Go to the documentation of this file.
1/*
2 * MMAL Video Decoder
3 * Copyright (c) 2015 rcombs
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * MMAL Video Decoder
25 */
26
27#include <bcm_host.h>
28#include <interface/mmal/mmal.h>
29#include <interface/mmal/mmal_parameters_video.h>
30#include <interface/mmal/util/mmal_util.h>
31#include <interface/mmal/util/mmal_util_params.h>
32#include <interface/mmal/util/mmal_default_components.h>
33#include <interface/mmal/vc/mmal_vc_api.h>
34#include <stdatomic.h>
35
36#include "avcodec.h"
37#include "codec_internal.h"
38#include "decode.h"
39#include "hwconfig.h"
40#include "internal.h"
41#include "libavutil/avassert.h"
42#include "libavutil/buffer.h"
43#include "libavutil/common.h"
44#include "libavutil/imgutils.h"
45#include "libavutil/mem.h"
46#include "libavutil/opt.h"
47#include "libavutil/log.h"
48
57
58// MMAL_POOL_T destroys all of its MMAL_BUFFER_HEADER_Ts. If we want correct
59// refcounting for AVFrames, we can free the MMAL_POOL_T only after all AVFrames
60// have been unreferenced.
61typedef struct FFPoolRef {
63 MMAL_POOL_T *pool;
64} FFPoolRef;
65
66typedef struct FFBufferRef {
67 MMAL_BUFFER_HEADER_T *buffer;
70
71typedef struct MMALDecodeContext {
75
76 MMAL_COMPONENT_T *decoder;
77 MMAL_QUEUE_T *queue_decoded_frames;
78 MMAL_POOL_T *pool_in;
80
81 // Waiting input packets. Because the libavcodec API requires decoding and
82 // returning packets in lockstep, it can happen that queue_decoded_frames
83 // contains almost all surfaces - then the decoder input queue can quickly
84 // fill up and won't accept new input either. Without consuming input, the
85 // libavcodec API can't return new frames, and we have a logical deadlock.
86 // This is avoided by queuing such buffers here.
88 /* Packet used to hold received packets temporarily; not owned by us. */
90
100
101// Assume decoder is guaranteed to produce output after at least this many
102// packets (where each packet contains 1 frame).
103#define MAX_DELAYED_FRAMES 16
104
108
110{
111 if (ref &&
112 atomic_fetch_add_explicit(&ref->refcount, -1, memory_order_acq_rel) == 1) {
113 mmal_pool_destroy(ref->pool);
114 av_free(ref);
115 }
116}
117
118static void ffmmal_release_frame(void *opaque, uint8_t *data)
119{
120 FFBufferRef *ref = (void *)data;
121
122 mmal_buffer_header_release(ref->buffer);
124
125 av_free(ref);
126}
127
128// Setup frame with a new reference to buffer. The buffer must have been
129// allocated from the given pool.
131 MMAL_BUFFER_HEADER_T *buffer)
132{
133 FFBufferRef *ref = av_mallocz(sizeof(*ref));
134 if (!ref)
135 return AVERROR(ENOMEM);
136
137 ref->pool = pool;
138 ref->buffer = buffer;
139
140 frame->buf[0] = av_buffer_create((void *)ref, sizeof(*ref),
143 if (!frame->buf[0]) {
144 av_free(ref);
145 return AVERROR(ENOMEM);
146 }
147
148 atomic_fetch_add_explicit(&ref->pool->refcount, 1, memory_order_relaxed);
149 mmal_buffer_header_acquire(buffer);
150
151 frame->format = AV_PIX_FMT_MMAL;
152 frame->data[3] = (uint8_t *)ref->buffer;
153 return 0;
154}
155
157{
159 MMAL_COMPONENT_T *decoder = ctx->decoder;
160 MMAL_BUFFER_HEADER_T *buffer;
161
162 mmal_port_disable(decoder->input[0]);
163 mmal_port_disable(decoder->output[0]);
164 mmal_port_disable(decoder->control);
165
166 mmal_port_flush(decoder->input[0]);
167 mmal_port_flush(decoder->output[0]);
168 mmal_port_flush(decoder->control);
169
170 while ((buffer = mmal_queue_get(ctx->queue_decoded_frames)))
171 mmal_buffer_header_release(buffer);
172
173 while (ctx->waiting_buffers) {
174 FFBufferEntry *buffer = ctx->waiting_buffers;
175
176 ctx->waiting_buffers = buffer->next;
177
178 if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
179 atomic_fetch_add(&ctx->packets_buffered, -1);
180
181 av_buffer_unref(&buffer->ref);
183 }
184 ctx->waiting_buffers_tail = NULL;
185
186 av_assert0(atomic_load(&ctx->packets_buffered) == 0);
187
188 ctx->frames_output = ctx->eos_received = ctx->eos_sent = ctx->packets_sent = ctx->extradata_sent = 0;
189}
190
192{
194
195 if (ctx->decoder)
196 ffmmal_stop_decoder(avctx);
197
198 mmal_component_destroy(ctx->decoder);
199 ctx->decoder = NULL;
200 mmal_queue_destroy(ctx->queue_decoded_frames);
201 mmal_pool_destroy(ctx->pool_in);
202 ffmmal_poolref_unref(ctx->pool_out);
203
204 mmal_vc_deinit();
205
206 return 0;
207}
208
209static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
210{
211 AVCodecContext *avctx = (AVCodecContext*)port->userdata;
213
214 if (!buffer->cmd) {
215 FFBufferEntry *entry = buffer->user_data;
216 av_buffer_unref(&entry->ref);
217 if (entry->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
218 atomic_fetch_add(&ctx->packets_buffered, -1);
219 av_free(entry);
220 }
221 mmal_buffer_header_release(buffer);
222}
223
224static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
225{
226 AVCodecContext *avctx = (AVCodecContext*)port->userdata;
228
229 mmal_queue_put(ctx->queue_decoded_frames, buffer);
230}
231
232static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
233{
234 AVCodecContext *avctx = (AVCodecContext*)port->userdata;
235 MMAL_STATUS_T status;
236
237 if (buffer->cmd == MMAL_EVENT_ERROR) {
238 status = *(uint32_t *)buffer->data;
239 av_log(avctx, AV_LOG_ERROR, "MMAL error %d on control port\n", (int)status);
240 } else {
241 av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on control port\n",
242 av_fourcc2str(buffer->cmd));
243 }
244
245 mmal_buffer_header_release(buffer);
246}
247
248// Feed free output buffers to the decoder.
250{
252 MMAL_BUFFER_HEADER_T *buffer;
253 MMAL_STATUS_T status;
254
255 if (!ctx->pool_out)
256 return AVERROR_UNKNOWN; // format change code failed with OOM previously
257
258 while ((buffer = mmal_queue_get(ctx->pool_out->pool->queue))) {
259 if ((status = mmal_port_send_buffer(ctx->decoder->output[0], buffer))) {
260 mmal_buffer_header_release(buffer);
261 av_log(avctx, AV_LOG_ERROR, "MMAL error %d when sending output buffer.\n", (int)status);
262 return AVERROR_UNKNOWN;
263 }
264 }
265
266 return 0;
267}
268
269static enum AVColorSpace ffmmal_csp_to_av_csp(MMAL_FOURCC_T fourcc)
270{
271 switch (fourcc) {
272 case MMAL_COLOR_SPACE_BT470_2_BG:
273 case MMAL_COLOR_SPACE_BT470_2_M:
274 case MMAL_COLOR_SPACE_ITUR_BT601: return AVCOL_SPC_BT470BG;
275 case MMAL_COLOR_SPACE_ITUR_BT709: return AVCOL_SPC_BT709;
276 case MMAL_COLOR_SPACE_FCC: return AVCOL_SPC_FCC;
277 case MMAL_COLOR_SPACE_SMPTE240M: return AVCOL_SPC_SMPTE240M;
278 default: return AVCOL_SPC_UNSPECIFIED;
279 }
280}
281
283{
285 MMAL_STATUS_T status;
286 int ret = 0;
287 MMAL_COMPONENT_T *decoder = ctx->decoder;
288 MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format;
289 MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type;
290
291 ffmmal_poolref_unref(ctx->pool_out);
292 if (!(ctx->pool_out = av_mallocz(sizeof(*ctx->pool_out)))) {
293 ret = AVERROR(ENOMEM);
294 goto fail;
295 }
296 atomic_init(&ctx->pool_out->refcount, 1);
297
298 if (!format_out)
299 goto fail;
300
301 if ((status = mmal_port_parameter_set_uint32(decoder->output[0], MMAL_PARAMETER_EXTRA_BUFFERS, ctx->extra_buffers)))
302 goto fail;
303
304 if ((status = mmal_port_parameter_set_boolean(decoder->output[0], MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS, 0)))
305 goto fail;
306
307 if (avctx->pix_fmt == AV_PIX_FMT_MMAL) {
308 format_out->encoding = MMAL_ENCODING_OPAQUE;
309 } else {
310 format_out->encoding_variant = format_out->encoding = MMAL_ENCODING_I420;
311 }
312
313 if ((status = mmal_port_format_commit(decoder->output[0])))
314 goto fail;
315
316 interlace_type.hdr.id = MMAL_PARAMETER_VIDEO_INTERLACE_TYPE;
317 interlace_type.hdr.size = sizeof(MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T);
318 status = mmal_port_parameter_get(decoder->output[0], &interlace_type.hdr);
319 if (status != MMAL_SUCCESS) {
320 av_log(avctx, AV_LOG_ERROR, "Cannot read MMAL interlace information!\n");
321 } else {
322 ctx->interlaced_frame = (interlace_type.eMode != MMAL_InterlaceProgressive);
323 ctx->top_field_first = (interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst);
324 }
325
326 if ((ret = ff_set_dimensions(avctx, format_out->es->video.crop.x + format_out->es->video.crop.width,
327 format_out->es->video.crop.y + format_out->es->video.crop.height)) < 0)
328 goto fail;
329
330 if (format_out->es->video.par.num && format_out->es->video.par.den) {
331 avctx->sample_aspect_ratio.num = format_out->es->video.par.num;
332 avctx->sample_aspect_ratio.den = format_out->es->video.par.den;
333 }
334 if (format_out->es->video.frame_rate.num && format_out->es->video.frame_rate.den) {
335 avctx->framerate.num = format_out->es->video.frame_rate.num;
336 avctx->framerate.den = format_out->es->video.frame_rate.den;
337 }
338
339 avctx->colorspace = ffmmal_csp_to_av_csp(format_out->es->video.color_space);
340
341 decoder->output[0]->buffer_size =
342 FFMAX(decoder->output[0]->buffer_size_min, decoder->output[0]->buffer_size_recommended);
343 decoder->output[0]->buffer_num =
344 FFMAX(decoder->output[0]->buffer_num_min, decoder->output[0]->buffer_num_recommended) + ctx->extra_buffers;
345 ctx->pool_out->pool = mmal_pool_create(decoder->output[0]->buffer_num,
346 decoder->output[0]->buffer_size);
347 if (!ctx->pool_out->pool) {
348 ret = AVERROR(ENOMEM);
349 goto fail;
350 }
351
352 return 0;
353
354fail:
355 return ret < 0 ? ret : AVERROR_UNKNOWN;
356}
357
359{
361 MMAL_STATUS_T status;
362 MMAL_ES_FORMAT_T *format_in;
363 MMAL_COMPONENT_T *decoder;
364 int ret = 0;
365
366 ctx->pkt = avctx->internal->in_pkt;
367
368 bcm_host_init();
369
370 if (mmal_vc_init()) {
371 av_log(avctx, AV_LOG_ERROR, "Cannot initialize MMAL VC driver!\n");
372 return AVERROR(ENOSYS);
373 }
374
375 if ((ret = ff_get_format(avctx, mmal_pixfmts)) < 0)
376 return ret;
377
378 avctx->pix_fmt = ret;
379
380 if ((status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &ctx->decoder)))
381 goto fail;
382
383 decoder = ctx->decoder;
384
385 format_in = decoder->input[0]->format;
386 format_in->type = MMAL_ES_TYPE_VIDEO;
387 switch (avctx->codec_id) {
389 format_in->encoding = MMAL_ENCODING_MP2V;
390 break;
392 format_in->encoding = MMAL_ENCODING_MP4V;
393 break;
394 case AV_CODEC_ID_VC1:
395 format_in->encoding = MMAL_ENCODING_WVC1;
396 break;
397 case AV_CODEC_ID_H264:
398 default:
399 format_in->encoding = MMAL_ENCODING_H264;
400 break;
401 }
402 format_in->es->video.width = FFALIGN(avctx->width, 32);
403 format_in->es->video.height = FFALIGN(avctx->height, 16);
404 format_in->es->video.crop.width = avctx->width;
405 format_in->es->video.crop.height = avctx->height;
406 format_in->es->video.frame_rate.num = 24000;
407 format_in->es->video.frame_rate.den = 1001;
408 format_in->es->video.par.num = avctx->sample_aspect_ratio.num;
409 format_in->es->video.par.den = avctx->sample_aspect_ratio.den;
410 format_in->flags = MMAL_ES_FORMAT_FLAG_FRAMED;
411
412 av_log(avctx, AV_LOG_DEBUG, "Using MMAL %s encoding.\n",
413 av_fourcc2str(format_in->encoding));
414
415#if HAVE_MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS
416 if (mmal_port_parameter_set_uint32(decoder->input[0], MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS,
417 -1 - ctx->extra_decoder_buffers)) {
418 av_log(avctx, AV_LOG_WARNING, "Could not set input buffering limit.\n");
419 }
420#endif
421
422 if ((status = mmal_port_format_commit(decoder->input[0])))
423 goto fail;
424
425 decoder->input[0]->buffer_num =
426 FFMAX(decoder->input[0]->buffer_num_min, 20);
427 decoder->input[0]->buffer_size =
428 FFMAX(decoder->input[0]->buffer_size_min, 512 * 1024);
429 ctx->pool_in = mmal_pool_create(decoder->input[0]->buffer_num, 0);
430 if (!ctx->pool_in) {
431 ret = AVERROR(ENOMEM);
432 goto fail;
433 }
434
435 if ((ret = ffmal_update_format(avctx)) < 0)
436 goto fail;
437
438 ctx->queue_decoded_frames = mmal_queue_create();
439 if (!ctx->queue_decoded_frames)
440 goto fail;
441
442 decoder->input[0]->userdata = (void*)avctx;
443 decoder->output[0]->userdata = (void*)avctx;
444 decoder->control->userdata = (void*)avctx;
445
446 if ((status = mmal_port_enable(decoder->control, control_port_cb)))
447 goto fail;
448 if ((status = mmal_port_enable(decoder->input[0], input_callback)))
449 goto fail;
450 if ((status = mmal_port_enable(decoder->output[0], output_callback)))
451 goto fail;
452
453 if ((status = mmal_component_enable(decoder)))
454 goto fail;
455
456 return 0;
457
458fail:
460 return ret < 0 ? ret : AVERROR_UNKNOWN;
461}
462
463static void ffmmal_flush(AVCodecContext *avctx)
464{
466 MMAL_COMPONENT_T *decoder = ctx->decoder;
467 MMAL_STATUS_T status;
468
469 ffmmal_stop_decoder(avctx);
470
471 if ((status = mmal_port_enable(decoder->control, control_port_cb)))
472 goto fail;
473 if ((status = mmal_port_enable(decoder->input[0], input_callback)))
474 goto fail;
475 if ((status = mmal_port_enable(decoder->output[0], output_callback)))
476 goto fail;
477
478 return;
479
480fail:
481 av_log(avctx, AV_LOG_ERROR, "MMAL flush error: %i\n", (int)status);
482}
483
484// Split packets and add them to the waiting_buffers list. We don't queue them
485// immediately, because it can happen that the decoder is temporarily blocked
486// (due to us not reading/returning enough output buffers) and won't accept
487// new input. (This wouldn't be an issue if MMAL input buffers always were
488// complete frames - then the input buffer just would have to be big enough.)
489// If is_extradata is set, send it as MMAL_BUFFER_HEADER_FLAG_CONFIG.
490static int ffmmal_add_packet(AVCodecContext *avctx, AVPacket *avpkt,
491 int is_extradata)
492{
494 const AVBufferRef *buf = NULL;
495 int size = 0;
496 uint8_t *data = (uint8_t *)"";
497 uint8_t *start;
498 int ret = 0;
499
500 if (avpkt->size) {
501 ret = av_packet_make_refcounted(avpkt);
502 if (ret < 0)
503 goto done;
504 buf = avpkt->buf;
505 data = avpkt->data;
506 size = avpkt->size;
507 if (!is_extradata)
508 ctx->packets_sent++;
509 } else {
510 if (ctx->eos_sent)
511 goto done;
512 if (!ctx->packets_sent) {
513 // Short-cut the flush logic to avoid upsetting MMAL.
514 ctx->eos_sent = 1;
515 ctx->eos_received = 1;
516 goto done;
517 }
518 }
519
520 start = data;
521
522 do {
524 if (!buffer) {
525 ret = AVERROR(ENOMEM);
526 goto done;
527 }
528
529 buffer->data = data;
530 buffer->length = FFMIN(size, ctx->decoder->input[0]->buffer_size);
531
532 if (is_extradata)
533 buffer->flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG;
534
535 if (data == start)
536 buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_START;
537
538 data += buffer->length;
539 size -= buffer->length;
540
541 buffer->pts = avpkt->pts == AV_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : avpkt->pts;
542 buffer->dts = avpkt->dts == AV_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : avpkt->dts;
543
544 if (!size) {
545 buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
546 atomic_fetch_add(&ctx->packets_buffered, 1);
547 }
548
549 if (!buffer->length) {
550 buffer->flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
551 ctx->eos_sent = 1;
552 }
553
554 if (buf) {
555 buffer->ref = av_buffer_ref(buf);
556 if (!buffer->ref) {
558 ret = AVERROR(ENOMEM);
559 goto done;
560 }
561 }
562
563 // Insert at end of the list
564 if (!ctx->waiting_buffers)
565 ctx->waiting_buffers = buffer;
566 if (ctx->waiting_buffers_tail)
567 ctx->waiting_buffers_tail->next = buffer;
568 ctx->waiting_buffers_tail = buffer;
569 } while (size);
570
571done:
572 av_packet_unref(avpkt);
573 return ret;
574}
575
576// Move prepared/split packets from waiting_buffers to the MMAL decoder.
578{
580
581 while (ctx->waiting_buffers) {
582 MMAL_BUFFER_HEADER_T *mbuffer;
584 MMAL_STATUS_T status;
585
586 mbuffer = mmal_queue_get(ctx->pool_in->queue);
587 if (!mbuffer)
588 return 0;
589
590 buffer = ctx->waiting_buffers;
591
592 mmal_buffer_header_reset(mbuffer);
593 mbuffer->cmd = 0;
594 mbuffer->pts = buffer->pts;
595 mbuffer->dts = buffer->dts;
596 mbuffer->flags = buffer->flags;
597 mbuffer->data = buffer->data;
598 mbuffer->length = buffer->length;
599 mbuffer->user_data = buffer;
600 mbuffer->alloc_size = ctx->decoder->input[0]->buffer_size;
601
602 // Remove from start of the list
603 ctx->waiting_buffers = buffer->next;
604 if (ctx->waiting_buffers_tail == buffer)
605 ctx->waiting_buffers_tail = NULL;
606
607 if ((status = mmal_port_send_buffer(ctx->decoder->input[0], mbuffer))) {
608 mmal_buffer_header_release(mbuffer);
609 av_buffer_unref(&buffer->ref);
610 if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
611 atomic_fetch_add(&ctx->packets_buffered, -1);
613 }
614
615 if (status) {
616 av_log(avctx, AV_LOG_ERROR, "MMAL error %d when sending input\n", (int)status);
617 return AVERROR_UNKNOWN;
618 }
619 }
620
621 return 0;
622}
623
625 MMAL_BUFFER_HEADER_T *buffer)
626{
628 int ret = 0;
629
630 if (ctx->interlaced_frame)
632 if (ctx->top_field_first)
634
635 if (avctx->pix_fmt == AV_PIX_FMT_MMAL) {
636 if (!ctx->pool_out)
637 return AVERROR_UNKNOWN; // format change code failed with OOM previously
638
639 if ((ret = ff_decode_frame_props(avctx, frame)) < 0)
640 goto done;
641
642 if ((ret = ffmmal_set_ref(frame, ctx->pool_out, buffer)) < 0)
643 goto done;
644 } else {
645 int w = FFALIGN(avctx->width, 32);
646 int h = FFALIGN(avctx->height, 16);
647 uint8_t *src[4];
648 int linesize[4];
649
650 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
651 goto done;
652
653 av_image_fill_arrays(src, linesize,
654 buffer->data + buffer->type->video.offset[0],
655 avctx->pix_fmt, w, h, 1);
656 av_image_copy2(frame->data, frame->linesize, src, linesize,
657 avctx->pix_fmt, avctx->width, avctx->height);
658 }
659
660 frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
661 frame->width = avctx->width;
662 frame->width = avctx->width;
663 frame->height = avctx->height;
664 frame->format = avctx->pix_fmt;
665
666 frame->pts = buffer->pts == MMAL_TIME_UNKNOWN ? AV_NOPTS_VALUE : buffer->pts;
667 frame->pkt_dts = AV_NOPTS_VALUE;
668
669done:
670 return ret;
671}
672
673// Fetch a decoded buffer and place it into the frame parameter.
674static int ffmmal_read_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame)
675{
677 MMAL_BUFFER_HEADER_T *buffer = NULL;
678 MMAL_STATUS_T status = 0;
679 int ret = 0;
680
681 if (ctx->eos_received)
682 goto done;
683
684 while (1) {
685 // To ensure decoding in lockstep with a constant delay between fed packets
686 // and output frames, we always wait until an output buffer is available.
687 // Except during start we don't know after how many input packets the decoder
688 // is going to return the first buffer, and we can't distinguish decoder
689 // being busy from decoder waiting for input. So just poll at the start and
690 // keep feeding new data to the buffer.
691 // We are pretty sure the decoder will produce output if we sent more input
692 // frames than what a H.264 decoder could logically delay. This avoids too
693 // excessive buffering.
694 // We also wait if we sent eos, but didn't receive it yet (think of decoding
695 // stream with a very low number of frames).
696 if (atomic_load(&ctx->packets_buffered) > MAX_DELAYED_FRAMES ||
697 (ctx->packets_sent && ctx->eos_sent)) {
698 // MMAL will ignore broken input packets, which means the frame we
699 // expect here may never arrive. Dealing with this correctly is
700 // complicated, so here's a hack to avoid that it freezes forever
701 // in this unlikely situation.
702 buffer = mmal_queue_timedwait(ctx->queue_decoded_frames, 100);
703 if (!buffer) {
704 av_log(avctx, AV_LOG_ERROR, "Did not get output frame from MMAL.\n");
705 ret = AVERROR_UNKNOWN;
706 goto done;
707 }
708 } else {
709 buffer = mmal_queue_get(ctx->queue_decoded_frames);
710 if (!buffer)
711 goto done;
712 }
713
714 ctx->eos_received |= !!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS);
715 if (ctx->eos_received)
716 goto done;
717
718 if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) {
719 MMAL_COMPONENT_T *decoder = ctx->decoder;
720 MMAL_EVENT_FORMAT_CHANGED_T *ev = mmal_event_format_changed_get(buffer);
721 MMAL_BUFFER_HEADER_T *stale_buffer;
722
723 av_log(avctx, AV_LOG_INFO, "Changing output format.\n");
724
725 if ((status = mmal_port_disable(decoder->output[0])))
726 goto done;
727
728 while ((stale_buffer = mmal_queue_get(ctx->queue_decoded_frames)))
729 mmal_buffer_header_release(stale_buffer);
730
731 mmal_format_copy(decoder->output[0]->format, ev->format);
732
733 if ((ret = ffmal_update_format(avctx)) < 0)
734 goto done;
735
736 if ((status = mmal_port_enable(decoder->output[0], output_callback)))
737 goto done;
738
739 if ((ret = ffmmal_fill_output_port(avctx)) < 0)
740 goto done;
741
742 if ((ret = ffmmal_fill_input_port(avctx)) < 0)
743 goto done;
744
745 mmal_buffer_header_release(buffer);
746 continue;
747 } else if (buffer->cmd) {
748 av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on output port\n",
749 av_fourcc2str(buffer->cmd));
750 goto done;
751 } else if (buffer->length == 0) {
752 // Unused output buffer that got drained after format change.
753 mmal_buffer_header_release(buffer);
754 continue;
755 }
756
757 ctx->frames_output++;
758
759 if ((ret = ffmal_copy_frame(avctx, frame, buffer)) < 0)
760 goto done;
761
762 *got_frame = 1;
763 break;
764 }
765
766done:
767 if (buffer)
768 mmal_buffer_header_release(buffer);
769 if (status && ret >= 0)
770 ret = AVERROR_UNKNOWN;
771 return ret;
772}
773
775{
777 AVPacket *const avpkt = ctx->pkt;
778 int ret = 0;
779 int got_frame = 0;
780
781 if (avctx->extradata_size && !ctx->extradata_sent) {
782 avpkt->data = avctx->extradata;
783 avpkt->size = avctx->extradata_size;
784 ctx->extradata_sent = 1;
785 if ((ret = ffmmal_add_packet(avctx, avpkt, 1)) < 0)
786 return ret;
787 }
788
789 ret = ff_decode_get_packet(avctx, avpkt);
790 if (ret == 0) {
791 if ((ret = ffmmal_add_packet(avctx, avpkt, 0)) < 0)
792 return ret;
793 } else if (ret < 0 && !(ret == AVERROR(EAGAIN)))
794 return ret;
795
796 if ((ret = ffmmal_fill_input_port(avctx)) < 0)
797 return ret;
798
799 if ((ret = ffmmal_fill_output_port(avctx)) < 0)
800 return ret;
801
802 if ((ret = ffmmal_read_frame(avctx, frame, &got_frame)) < 0)
803 return ret;
804
805 // ffmmal_read_frame() can block for a while. Since the decoder is
806 // asynchronous, it's a good idea to fill the ports again.
807
808 if ((ret = ffmmal_fill_output_port(avctx)) < 0)
809 return ret;
810
811 if ((ret = ffmmal_fill_input_port(avctx)) < 0)
812 return ret;
813
814 if (!got_frame && ret == 0)
815 return AVERROR(EAGAIN);
816 else
817 return ret;
818}
819
821 HW_CONFIG_INTERNAL(MMAL),
822 NULL
823};
824
825static const AVOption options[]={
826 {"extra_buffers", "extra buffers", offsetof(MMALDecodeContext, extra_buffers), AV_OPT_TYPE_INT, {.i64 = 10}, 0, 256, 0},
827 {"extra_decoder_buffers", "extra MMAL internal buffered frames", offsetof(MMALDecodeContext, extra_decoder_buffers), AV_OPT_TYPE_INT, {.i64 = 10}, 0, 256, 0},
828 {NULL}
829};
830
831static const AVClass ffmmal_dec_class = {
832 .class_name = "mmal_dec",
833 .item_name = av_default_item_name,
834 .option = options,
835 .version = LIBAVUTIL_VERSION_INT,
836};
837
838#define FFMMAL_DEC(NAME, ID) \
839 const FFCodec ff_##NAME##_mmal_decoder = { \
840 .p.name = #NAME "_mmal", \
841 CODEC_LONG_NAME(#NAME " (mmal)"), \
842 .p.type = AVMEDIA_TYPE_VIDEO, \
843 .p.id = ID, \
844 .priv_data_size = sizeof(MMALDecodeContext), \
845 .init = ffmmal_init_decoder, \
846 .close = ffmmal_close_decoder, \
847 FF_CODEC_RECEIVE_FRAME_CB(ffmmal_receive_frame), \
848 .flush = ffmmal_flush, \
849 .p.priv_class = &ffmmal_dec_class, \
850 .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \
851 .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \
852 .hw_configs = mmal_hw_configs, \
853 .p.wrapper_name = "mmal", \
854 };
855
#define entry
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
Libavcodec external API header.
refcounted data buffer API
common internal and external API header
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition decode.c:1777
int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
Set various frame properties from the codec context / packet data.
Definition decode.c:1598
int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt)
Called by decoders to get the next packet for decoding.
Definition decode.c:254
int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
Select the (possibly hardware accelerated) pixel format.
Definition decode.c:1229
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Definition utils.c:91
static AVFrame * frame
#define atomic_fetch_add_explicit(object, operand, order)
Definition stdatomic.h:149
intptr_t atomic_int
Definition stdatomic.h:55
#define atomic_load(object)
Definition stdatomic.h:93
#define atomic_init(obj, value)
Definition stdatomic.h:33
#define fail
Definition test.h:479
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_CODEC_ID_H264
Definition codec_id.h:77
@ AV_CODEC_ID_VC1
Definition codec_id.h:120
@ AV_CODEC_ID_MPEG4
Definition codec_id.h:62
@ AV_CODEC_ID_MPEG2VIDEO
preferred ID for MPEG-1/2 video decoding
Definition codec_id.h:52
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
int av_packet_make_refcounted(AVPacket *pkt)
Ensure the data described by a given packet is reference counted.
Definition packet.c:497
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition buffer.c:139
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:103
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition buffer.h:114
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition buffer.c:55
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR(e)
Definition error.h:45
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition frame.h:695
#define AV_FRAME_FLAG_TOP_FIELD_FIRST
A flag to mark frames where the top field is displayed first if the content is interlaced.
Definition frame.h:700
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
#define av_fourcc2str(fourcc)
Definition avutil.h:323
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align)
Setup the data pointers and linesizes based on the specified image parameters and the provided array.
Definition imgutils.c:446
static void av_image_copy2(uint8_t *const dst_data[4], const int dst_linesizes[4], uint8_t *const src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Wrapper around av_image_copy() to workaround the limitation that the conversion from uint8_t * const ...
Definition imgutils.h:184
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define HW_CONFIG_INTERNAL(format)
Definition hwconfig.h:54
misc image utilities
static const chunk_decoder decoder[8]
Definition dfa.c:331
common internal api header.
#define av_cold
Definition attributes.h:117
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
#define FFALIGN(x, a)
Definition macros.h:78
Memory handling functions.
static av_cold int ffmmal_close_decoder(AVCodecContext *avctx)
Definition mmaldec.c:191
static int ffmmal_fill_input_port(AVCodecContext *avctx)
Definition mmaldec.c:577
static int ffmal_update_format(AVCodecContext *avctx)
Definition mmaldec.c:282
static av_cold int ffmmal_init_decoder(AVCodecContext *avctx)
Definition mmaldec.c:358
static void ffmmal_release_frame(void *opaque, uint8_t *data)
Definition mmaldec.c:118
static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
Definition mmaldec.c:224
#define FFMMAL_DEC(NAME, ID)
Definition mmaldec.c:838
static const AVClass ffmmal_dec_class
Definition mmaldec.c:831
static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
Definition mmaldec.c:209
static int ffmmal_set_ref(AVFrame *frame, FFPoolRef *pool, MMAL_BUFFER_HEADER_T *buffer)
Definition mmaldec.c:130
#define MAX_DELAYED_FRAMES
Definition mmaldec.c:103
static int ffmal_copy_frame(AVCodecContext *avctx, AVFrame *frame, MMAL_BUFFER_HEADER_T *buffer)
Definition mmaldec.c:624
static const AVCodecHWConfigInternal *const mmal_hw_configs[]
Definition mmaldec.c:820
static void ffmmal_poolref_unref(FFPoolRef *ref)
Definition mmaldec.c:109
static void ffmmal_stop_decoder(AVCodecContext *avctx)
Definition mmaldec.c:156
static int ffmmal_read_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame)
Definition mmaldec.c:674
static void ffmmal_flush(AVCodecContext *avctx)
Definition mmaldec.c:463
static enum AVPixelFormat mmal_pixfmts[]
Definition mmaldec.c:105
static enum AVColorSpace ffmmal_csp_to_av_csp(MMAL_FOURCC_T fourcc)
Definition mmaldec.c:269
static int ffmmal_add_packet(AVCodecContext *avctx, AVPacket *avpkt, int is_extradata)
Definition mmaldec.c:490
static int ffmmal_fill_output_port(AVCodecContext *avctx)
Definition mmaldec.c:249
static int ffmmal_receive_frame(AVCodecContext *avctx, AVFrame *frame)
Definition mmaldec.c:774
static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
Definition mmaldec.c:232
const char data[16]
Definition mxf.c:149
AVOptions.
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_MMAL
HW acceleration though MMAL, data[3] contains a pointer to the MMAL_BUFFER_HEADER_T structure.
Definition pixfmt.h:252
AVColorSpace
YUV colorspace type.
Definition pixfmt.h:706
@ AVCOL_SPC_BT709
also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / derived in SMPTE RP 177 Annex B
Definition pixfmt.h:708
@ AVCOL_SPC_BT470BG
also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601
Definition pixfmt.h:712
@ AVCOL_SPC_UNSPECIFIED
Definition pixfmt.h:709
@ AVCOL_SPC_FCC
FCC Title 47 Code of Federal Regulations 73.682 (a)(20)
Definition pixfmt.h:711
@ AVCOL_SPC_SMPTE240M
derived from 170M primaries and D65 white point, 170M is derived from BT470 System M's primaries
Definition pixfmt.h:714
A reference to a data buffer.
Definition buffer.h:82
Describe the class of an AVClass context structure.
Definition log.h:76
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
AVRational framerate
Definition avcodec.h:563
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown) That is the width of a pixel divided by the height of the pixel.
Definition avcodec.h:628
enum AVColorSpace colorspace
YUV colorspace type.
Definition avcodec.h:671
uint8_t * extradata
Out-of-band global headers that may be used by some codecs.
Definition avcodec.h:526
enum AVCodecID codec_id
Definition avcodec.h:453
int extradata_size
Definition avcodec.h:527
struct AVCodecInternal * internal
Private context used for internal data.
Definition avcodec.h:478
void * priv_data
Definition avcodec.h:470
AVPacket * in_pkt
This packet is used to hold the packet given to decoders implementing the .decode API; it is unused b...
Definition internal.h:83
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
AVBufferRef * buf
A reference to the reference-counted buffer where the packet data is stored.
Definition packet.h:586
int size
Definition packet.h:604
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition packet.h:596
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition packet.h:602
uint8_t * data
Definition packet.h:603
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
size_t length
Definition mmaldec.c:52
AVBufferRef * ref
Definition mmaldec.c:50
int64_t pts
Definition mmaldec.c:53
struct FFBufferEntry * next
Definition mmaldec.c:55
void * data
Definition mmaldec.c:51
int64_t dts
Definition mmaldec.c:53
FFPoolRef * pool
Definition mmaldec.c:68
MMAL_BUFFER_HEADER_T * buffer
Definition mmaldec.c:67
MMAL_POOL_T * pool
Definition mmaldec.c:63
atomic_int refcount
Definition mmaldec.c:62
AVClass * av_class
Definition mmaldec.c:72
int64_t packets_sent
Definition mmaldec.c:91
MMAL_POOL_T * pool_in
Definition mmaldec.c:78
int64_t frames_output
Definition mmaldec.c:93
FFBufferEntry * waiting_buffers_tail
Definition mmaldec.c:87
MMAL_QUEUE_T * queue_decoded_frames
Definition mmaldec.c:77
AVPacket * pkt
Definition mmaldec.c:89
FFBufferEntry * waiting_buffers
Definition mmaldec.c:87
atomic_int packets_buffered
Definition mmaldec.c:92
FFPoolRef * pool_out
Definition mmaldec.c:79
MMAL_COMPONENT_T * decoder
Definition mmaldec.c:76
int extra_decoder_buffers
Definition mmaldec.c:74
#define av_free(p)
#define av_mallocz(s)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static int ref[MAX_W *MAX_W]
static AVFormatContext * ctx
Definition movenc.c:49
static char buffer[20]
Definition seek.c:32
int size
uint32_t fourcc
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:137