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