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