blob: e42591110fecd631b85a8a3c6ebad490a541614e [file] [log] [blame]
wm4c4845612015-03-27 22:04:081/*
2 * MMAL Video Decoder
rcombseabf5e62021-01-20 07:02:563 * Copyright (c) 2015 rcombs
wm4c4845612015-03-27 22:04:084 *
Michael Niedermayer268ff172015-03-29 09:32:245 * This file is part of FFmpeg.
wm4c4845612015-03-27 22:04:086 *
Michael Niedermayer268ff172015-03-29 09:32:247 * FFmpeg is free software; you can redistribute it and/or
wm4c4845612015-03-27 22:04:088 * 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 *
Michael Niedermayer268ff172015-03-29 09:32:2412 * FFmpeg is distributed in the hope that it will be useful,
wm4c4845612015-03-27 22:04:0813 * 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
Michael Niedermayer268ff172015-03-29 09:32:2418 * License along with FFmpeg; if not, write to the Free Software
wm4c4845612015-03-27 22:04:0819 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * MMAL Video Decoder
25 */
26
wm42de76502015-04-13 17:17:5927#include <bcm_host.h>
28#include <interface/mmal/mmal.h>
wm4b7ab6e12015-09-08 17:42:2429#include <interface/mmal/mmal_parameters_video.h>
wm42de76502015-04-13 17:17:5930#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>
wm449e531f2015-04-13 17:18:0033#include <interface/mmal/vc/mmal_vc_api.h>
Anton Khirnov8385ba52016-07-17 20:24:3534#include <stdatomic.h>
wm42de76502015-04-13 17:17:5935
wm4c4845612015-03-27 22:04:0836#include "avcodec.h"
Andreas Rheinhardta688f3c2022-03-16 17:18:2837#include "codec_internal.h"
James Almerc56d7872020-08-16 14:43:4838#include "decode.h"
Mark Thompson2594f6a2020-04-13 15:33:1439#include "hwconfig.h"
wm4c4845612015-03-27 22:04:0840#include "internal.h"
wm4c4845612015-03-27 22:04:0841#include "libavutil/avassert.h"
42#include "libavutil/buffer.h"
43#include "libavutil/common.h"
Martin Storsjöb8e899f2016-04-12 07:48:1044#include "libavutil/imgutils.h"
Andreas Rheinhardt790f7932024-03-25 00:30:3745#include "libavutil/mem.h"
wm4c4845612015-03-27 22:04:0846#include "libavutil/opt.h"
47#include "libavutil/log.h"
48
wm4c4845612015-03-27 22:04:0849typedef struct FFBufferEntry {
50 AVBufferRef *ref;
51 void *data;
52 size_t length;
53 int64_t pts, dts;
54 int flags;
55 struct FFBufferEntry *next;
56} FFBufferEntry;
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 {
Anton Khirnov8385ba52016-07-17 20:24:3562 atomic_int refcount;
wm4c4845612015-03-27 22:04:0863 MMAL_POOL_T *pool;
64} FFPoolRef;
65
66typedef struct FFBufferRef {
67 MMAL_BUFFER_HEADER_T *buffer;
68 FFPoolRef *pool;
69} FFBufferRef;
70
71typedef struct MMALDecodeContext {
72 AVClass *av_class;
73 int extra_buffers;
wm414a90c92016-01-28 16:24:5374 int extra_decoder_buffers;
wm4c4845612015-03-27 22:04:0875
wm4c4845612015-03-27 22:04:0876 MMAL_COMPONENT_T *decoder;
77 MMAL_QUEUE_T *queue_decoded_frames;
78 MMAL_POOL_T *pool_in;
79 FFPoolRef *pool_out;
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.
87 FFBufferEntry *waiting_buffers, *waiting_buffers_tail;
Ho Ming Shunb54377b2021-09-24 09:04:3588 /* Packet used to hold received packets temporarily; not owned by us. */
89 AVPacket *pkt;
wm4c4845612015-03-27 22:04:0890
91 int64_t packets_sent;
Anton Khirnov8385ba52016-07-17 20:24:3592 atomic_int packets_buffered;
wm4c4845612015-03-27 22:04:0893 int64_t frames_output;
94 int eos_received;
95 int eos_sent;
wm4f290e482015-09-24 06:49:4196 int extradata_sent;
Jens Zillerbc7066f2016-08-14 14:44:3997 int interlaced_frame;
98 int top_field_first;
wm4c4845612015-03-27 22:04:0899} MMALDecodeContext;
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
Andreas Rheinhardt687a2872024-02-05 18:58:20105static const enum AVPixelFormat mmal_pixfmts[] = {
106 AV_PIX_FMT_MMAL, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
107};
108
wm4c4845612015-03-27 22:04:08109static void ffmmal_poolref_unref(FFPoolRef *ref)
110{
Anton Khirnov8385ba52016-07-17 20:24:35111 if (ref &&
112 atomic_fetch_add_explicit(&ref->refcount, -1, memory_order_acq_rel) == 1) {
wm4c4845612015-03-27 22:04:08113 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);
123 ffmmal_poolref_unref(ref->pool);
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.
130static int ffmmal_set_ref(AVFrame *frame, FFPoolRef *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),
141 ffmmal_release_frame, NULL,
142 AV_BUFFER_FLAG_READONLY);
143 if (!frame->buf[0]) {
144 av_free(ref);
145 return AVERROR(ENOMEM);
146 }
147
Anton Khirnov8385ba52016-07-17 20:24:35148 atomic_fetch_add_explicit(&ref->pool->refcount, 1, memory_order_relaxed);
wm4c4845612015-03-27 22:04:08149 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
156static void ffmmal_stop_decoder(AVCodecContext *avctx)
157{
158 MMALDecodeContext *ctx = avctx->priv_data;
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
wm4a55fbfa2015-11-06 12:02:16178 if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
Anton Khirnov8385ba52016-07-17 20:24:35179 atomic_fetch_add(&ctx->packets_buffered, -1);
wm4a55fbfa2015-11-06 12:02:16180
wm4c4845612015-03-27 22:04:08181 av_buffer_unref(&buffer->ref);
182 av_free(buffer);
183 }
184 ctx->waiting_buffers_tail = NULL;
185
Anton Khirnov8385ba52016-07-17 20:24:35186 av_assert0(atomic_load(&ctx->packets_buffered) == 0);
wm439f01e32015-09-23 18:27:25187
wm4f290e482015-09-24 06:49:41188 ctx->frames_output = ctx->eos_received = ctx->eos_sent = ctx->packets_sent = ctx->extradata_sent = 0;
wm4c4845612015-03-27 22:04:08189}
190
191static av_cold int ffmmal_close_decoder(AVCodecContext *avctx)
192{
193 MMALDecodeContext *ctx = avctx->priv_data;
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
wm449e531f2015-04-13 17:18:00204 mmal_vc_deinit();
205
wm4c4845612015-03-27 22:04:08206 return 0;
207}
208
209static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
210{
wm439f01e32015-09-23 18:27:25211 AVCodecContext *avctx = (AVCodecContext*)port->userdata;
212 MMALDecodeContext *ctx = avctx->priv_data;
213
wm4c4845612015-03-27 22:04:08214 if (!buffer->cmd) {
wm465db4892015-09-23 18:27:24215 FFBufferEntry *entry = buffer->user_data;
216 av_buffer_unref(&entry->ref);
wm439f01e32015-09-23 18:27:25217 if (entry->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
Anton Khirnov8385ba52016-07-17 20:24:35218 atomic_fetch_add(&ctx->packets_buffered, -1);
wm465db4892015-09-23 18:27:24219 av_free(entry);
wm4c4845612015-03-27 22:04:08220 }
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;
227 MMALDecodeContext *ctx = avctx->priv_data;
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 {
Clément Bœsch67e370e2017-03-26 23:31:37241 av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on control port\n",
242 av_fourcc2str(buffer->cmd));
wm4c4845612015-03-27 22:04:08243 }
244
245 mmal_buffer_header_release(buffer);
246}
247
248// Feed free output buffers to the decoder.
249static int ffmmal_fill_output_port(AVCodecContext *avctx)
250{
251 MMALDecodeContext *ctx = avctx->priv_data;
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
282static int ffmal_update_format(AVCodecContext *avctx)
283{
284 MMALDecodeContext *ctx = avctx->priv_data;
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;
Jens Zillerbc7066f2016-08-14 14:44:39289 MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type;
wm4c4845612015-03-27 22:04:08290
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 }
Wan-Teh Changd82d5372016-11-30 19:52:41296 atomic_init(&ctx->pool_out->refcount, 1);
wm4c4845612015-03-27 22:04:08297
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
wm4b7ab6e12015-09-08 17:42:24304 if ((status = mmal_port_parameter_set_boolean(decoder->output[0], MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS, 0)))
305 goto fail;
306
wm4c4845612015-03-27 22:04:08307 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
Jens Zillerbc7066f2016-08-14 14:44:39316 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
wm4c4845612015-03-27 22:04:08326 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 }
Jens Zillerbc7066f2016-08-14 14:44:39334 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 }
wm4c4845612015-03-27 22:04:08338
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
358static av_cold int ffmmal_init_decoder(AVCodecContext *avctx)
359{
360 MMALDecodeContext *ctx = avctx->priv_data;
361 MMAL_STATUS_T status;
362 MMAL_ES_FORMAT_T *format_in;
363 MMAL_COMPONENT_T *decoder;
364 int ret = 0;
365
Ho Ming Shunb54377b2021-09-24 09:04:35366 ctx->pkt = avctx->internal->in_pkt;
367
wm4c4845612015-03-27 22:04:08368 bcm_host_init();
369
wm449e531f2015-04-13 17:18:00370 if (mmal_vc_init()) {
371 av_log(avctx, AV_LOG_ERROR, "Cannot initialize MMAL VC driver!\n");
372 return AVERROR(ENOSYS);
373 }
374
Andreas Rheinhardt687a2872024-02-05 18:58:20375 if ((ret = ff_get_format(avctx, mmal_pixfmts)) < 0)
wm4c4845612015-03-27 22:04:08376 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;
Julian Scheel7ebe12f2015-10-21 15:10:48387 switch (avctx->codec_id) {
Clément Bœschd16aefe2016-06-21 11:35:31388 case AV_CODEC_ID_MPEG2VIDEO:
389 format_in->encoding = MMAL_ENCODING_MP2V;
390 break;
391 case AV_CODEC_ID_MPEG4:
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;
Julian Scheel7ebe12f2015-10-21 15:10:48401 }
wm4c4845612015-03-27 22:04:08402 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
Clément Bœsch67e370e2017-03-26 23:31:37412 av_log(avctx, AV_LOG_DEBUG, "Using MMAL %s encoding.\n",
413 av_fourcc2str(format_in->encoding));
wm4d27a12c2016-01-28 16:23:46414
wm474beead2016-04-14 10:21:26415#if HAVE_MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS
wm414a90c92016-01-28 16:24:53416 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 }
wm474beead2016-04-14 10:21:26420#endif
wm414a90c92016-01-28 16:24:53421
wm4c4845612015-03-27 22:04:08422 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:
459 ffmmal_close_decoder(avctx);
460 return ret < 0 ? ret : AVERROR_UNKNOWN;
461}
462
463static void ffmmal_flush(AVCodecContext *avctx)
464{
465 MMALDecodeContext *ctx = avctx->priv_data;
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.)
wm4f290e482015-09-24 06:49:41489// 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)
wm4c4845612015-03-27 22:04:08492{
493 MMALDecodeContext *ctx = avctx->priv_data;
Andreas Rheinhardt9644ee22021-12-09 11:37:18494 const AVBufferRef *buf = NULL;
wm4c4845612015-03-27 22:04:08495 int size = 0;
496 uint8_t *data = (uint8_t *)"";
497 uint8_t *start;
498 int ret = 0;
499
wm4c4845612015-03-27 22:04:08500 if (avpkt->size) {
Andreas Rheinhardt9644ee22021-12-09 11:37:18501 ret = av_packet_make_refcounted(avpkt);
502 if (ret < 0)
wm4c4845612015-03-27 22:04:08503 goto done;
Andreas Rheinhardt9644ee22021-12-09 11:37:18504 buf = avpkt->buf;
505 data = avpkt->data;
506 size = avpkt->size;
wm4f290e482015-09-24 06:49:41507 if (!is_extradata)
508 ctx->packets_sent++;
wm467db57e2015-08-11 10:11:04509 } else {
wm4dafe4cd2015-11-10 12:47:01510 if (ctx->eos_sent)
511 goto done;
wm467db57e2015-08-11 10:11:04512 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 }
wm4c4845612015-03-27 22:04:08518 }
519
520 start = data;
521
522 do {
523 FFBufferEntry *buffer = av_mallocz(sizeof(*buffer));
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
wm4f290e482015-09-24 06:49:41532 if (is_extradata)
533 buffer->flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG;
534
wm4c4845612015-03-27 22:04:08535 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
wm439f01e32015-09-23 18:27:25544 if (!size) {
wm4c4845612015-03-27 22:04:08545 buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
Anton Khirnov8385ba52016-07-17 20:24:35546 atomic_fetch_add(&ctx->packets_buffered, 1);
wm439f01e32015-09-23 18:27:25547 }
wm4c4845612015-03-27 22:04:08548
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) {
557 av_free(buffer);
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:
Ho Ming Shunb54377b2021-09-24 09:04:35572 av_packet_unref(avpkt);
wm4c4845612015-03-27 22:04:08573 return ret;
574}
575
576// Move prepared/split packets from waiting_buffers to the MMAL decoder.
577static int ffmmal_fill_input_port(AVCodecContext *avctx)
578{
579 MMALDecodeContext *ctx = avctx->priv_data;
580
581 while (ctx->waiting_buffers) {
582 MMAL_BUFFER_HEADER_T *mbuffer;
583 FFBufferEntry *buffer;
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;
wm465db4892015-09-23 18:27:24599 mbuffer->user_data = buffer;
wm4c4845612015-03-27 22:04:08600 mbuffer->alloc_size = ctx->decoder->input[0]->buffer_size;
601
wm4c4845612015-03-27 22:04:08602 // 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;
wm465db4892015-09-23 18:27:24606
607 if ((status = mmal_port_send_buffer(ctx->decoder->input[0], mbuffer))) {
608 mmal_buffer_header_release(mbuffer);
609 av_buffer_unref(&buffer->ref);
wm439f01e32015-09-23 18:27:25610 if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
Anton Khirnov8385ba52016-07-17 20:24:35611 atomic_fetch_add(&ctx->packets_buffered, -1);
wm465db4892015-09-23 18:27:24612 av_free(buffer);
613 }
wm4c4845612015-03-27 22:04:08614
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
624static int ffmal_copy_frame(AVCodecContext *avctx, AVFrame *frame,
625 MMAL_BUFFER_HEADER_T *buffer)
626{
627 MMALDecodeContext *ctx = avctx->priv_data;
628 int ret = 0;
629
James Almer2f561ba2023-04-11 18:02:14630 if (ctx->interlaced_frame)
631 frame->flags |= AV_FRAME_FLAG_INTERLACED;
632 if (ctx->top_field_first)
633 frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
Jens Zillerbc7066f2016-08-14 14:44:39634
wm4c4845612015-03-27 22:04:08635 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);
Martin Storsjöb8e899f2016-04-12 07:48:10647 uint8_t *src[4];
648 int linesize[4];
wm4c4845612015-03-27 22:04:08649
650 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
651 goto done;
652
Martin Storsjöb8e899f2016-04-12 07:48:10653 av_image_fill_arrays(src, linesize,
654 buffer->data + buffer->type->video.offset[0],
655 avctx->pix_fmt, w, h, 1);
Andreas Rheinhardt423b6a72023-09-06 22:09:10656 av_image_copy2(frame->data, frame->linesize, src, linesize,
657 avctx->pix_fmt, avctx->width, avctx->height);
wm4c4845612015-03-27 22:04:08658 }
659
Ho Ming Shunb54377b2021-09-24 09:04:35660 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
Anton Khirnov32c83592016-03-19 20:45:24666 frame->pts = buffer->pts == MMAL_TIME_UNKNOWN ? AV_NOPTS_VALUE : buffer->pts;
wm499404592015-09-08 17:42:26667 frame->pkt_dts = AV_NOPTS_VALUE;
wm4c4845612015-03-27 22:04:08668
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{
676 MMALDecodeContext *ctx = avctx->priv_data;
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
Clément Bœschd16aefe2016-06-21 11:35:31692 // frames than what a H.264 decoder could logically delay. This avoids too
wm4c4845612015-03-27 22:04:08693 // 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).
Anton Khirnov8385ba52016-07-17 20:24:35696 if (atomic_load(&ctx->packets_buffered) > MAX_DELAYED_FRAMES ||
wm467db57e2015-08-11 10:11:04697 (ctx->packets_sent && ctx->eos_sent)) {
wm4750f72d2015-08-11 09:26:19698 // 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 }
wm4c4845612015-03-27 22:04:08708 } else {
709 buffer = mmal_queue_get(ctx->queue_decoded_frames);
wm4750f72d2015-08-11 09:26:19710 if (!buffer)
711 goto done;
wm4c4845612015-03-27 22:04:08712 }
wm4c4845612015-03-27 22:04:08713
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) {
Clément Bœsch67e370e2017-03-26 23:31:37748 av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on output port\n",
749 av_fourcc2str(buffer->cmd));
wm4c4845612015-03-27 22:04:08750 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
Ho Ming Shunb54377b2021-09-24 09:04:35774static int ffmmal_receive_frame(AVCodecContext *avctx, AVFrame *frame)
wm4c4845612015-03-27 22:04:08775{
wm4f290e482015-09-24 06:49:41776 MMALDecodeContext *ctx = avctx->priv_data;
Ho Ming Shunb54377b2021-09-24 09:04:35777 AVPacket *const avpkt = ctx->pkt;
wm4c4845612015-03-27 22:04:08778 int ret = 0;
Ho Ming Shunb54377b2021-09-24 09:04:35779 int got_frame = 0;
wm4c4845612015-03-27 22:04:08780
wm4f290e482015-09-24 06:49:41781 if (avctx->extradata_size && !ctx->extradata_sent) {
Ho Ming Shun6f0e8b92021-09-24 09:04:37782 avpkt->data = avctx->extradata;
783 avpkt->size = avctx->extradata_size;
wm4f290e482015-09-24 06:49:41784 ctx->extradata_sent = 1;
Ho Ming Shun6f0e8b92021-09-24 09:04:37785 if ((ret = ffmmal_add_packet(avctx, avpkt, 1)) < 0)
wm4f290e482015-09-24 06:49:41786 return ret;
787 }
788
Ho Ming Shunb54377b2021-09-24 09:04:35789 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)))
wm4c4845612015-03-27 22:04:08794 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
Ho Ming Shunb54377b2021-09-24 09:04:35802 if ((ret = ffmmal_read_frame(avctx, frame, &got_frame)) < 0)
wm4c4845612015-03-27 22:04:08803 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
Ho Ming Shunb54377b2021-09-24 09:04:35814 if (!got_frame && ret == 0)
815 return AVERROR(EAGAIN);
816 else
817 return ret;
wm4c4845612015-03-27 22:04:08818}
819
Mark Thompsoncd322792020-11-08 18:51:15820static const AVCodecHWConfigInternal *const mmal_hw_configs[] = {
Mark Thompson758fbc52017-10-25 23:18:40821 HW_CONFIG_INTERNAL(MMAL),
822 NULL
823};
824
wm4c4845612015-03-27 22:04:08825static const AVOption options[]={
826 {"extra_buffers", "extra buffers", offsetof(MMALDecodeContext, extra_buffers), AV_OPT_TYPE_INT, {.i64 = 10}, 0, 256, 0},
wm414a90c92016-01-28 16:24:53827 {"extra_decoder_buffers", "extra MMAL internal buffered frames", offsetof(MMALDecodeContext, extra_decoder_buffers), AV_OPT_TYPE_INT, {.i64 = 10}, 0, 256, 0},
wm4c4845612015-03-27 22:04:08828 {NULL}
829};
830
Andreas Rheinhardt7fe5c7f2021-12-09 11:58:02831static const AVClass ffmmal_dec_class = {
832 .class_name = "mmal_dec",
Anton Khirnov08bebeb2024-01-19 12:33:28833 .item_name = av_default_item_name,
Andreas Rheinhardt7fe5c7f2021-12-09 11:58:02834 .option = options,
835 .version = LIBAVUTIL_VERSION_INT,
836};
wm4c4845612015-03-27 22:04:08837
Julian Scheel7ebe12f2015-10-21 15:10:48838#define FFMMAL_DEC(NAME, ID) \
Andreas Rheinhardt20f97272022-03-16 20:09:54839 const FFCodec ff_##NAME##_mmal_decoder = { \
840 .p.name = #NAME "_mmal", \
Andreas Rheinhardt48286d42022-08-29 11:38:02841 CODEC_LONG_NAME(#NAME " (mmal)"), \
Andreas Rheinhardt20f97272022-03-16 20:09:54842 .p.type = AVMEDIA_TYPE_VIDEO, \
843 .p.id = ID, \
Julian Scheel7ebe12f2015-10-21 15:10:48844 .priv_data_size = sizeof(MMALDecodeContext), \
845 .init = ffmmal_init_decoder, \
846 .close = ffmmal_close_decoder, \
Andreas Rheinhardt4243da42022-03-30 21:28:24847 FF_CODEC_RECEIVE_FRAME_CB(ffmmal_receive_frame), \
Julian Scheel7ebe12f2015-10-21 15:10:48848 .flush = ffmmal_flush, \
Andreas Rheinhardt20f97272022-03-16 20:09:54849 .p.priv_class = &ffmmal_dec_class, \
850 .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \
Zhao Zhilie8a49b12023-11-20 20:05:08851 .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \
Mark Thompson758fbc52017-10-25 23:18:40852 .hw_configs = mmal_hw_configs, \
Andreas Rheinhardt20f97272022-03-16 20:09:54853 .p.wrapper_name = "mmal", \
Julian Scheel7ebe12f2015-10-21 15:10:48854 };
855
856FFMMAL_DEC(h264, AV_CODEC_ID_H264)
857FFMMAL_DEC(mpeg2, AV_CODEC_ID_MPEG2VIDEO)
wm47b1b53f2016-01-28 16:24:40858FFMMAL_DEC(mpeg4, AV_CODEC_ID_MPEG4)
wm4b07cbf62015-11-06 11:59:16859FFMMAL_DEC(vc1, AV_CODEC_ID_VC1)