Hello, I needed to acquire mjpeg from a v4l2 uvc webcam in a Raspberry pi, and I saw mmaldec lacked mjpeg and also was doing an unnecessary copy.
I used two patches I found in the mailing list archives to enable mjpeg mmaldec and then wrote one that avoids the copy. It works fine for me but I have not run 'fate' yet. I'm in a cross-building situation and I have yet to learn how that works. In a Raspberry Pi 1 Model B now it can 640x480 30fps mjpeg->h264_omx with 25% of cpu (as "top" shows). Before these three patches, 640x480 YUY2->h264_omx could do only 20fps and "top" showed 50% of cpu. A Raspberry Pi 2 can do easily 30fps 1280x720 mjpeg->h264_omx as well. It'd be a lot easier for me if these patches were upstream so I'm interested in the code getting in. I'm new in ffmpeg so I may have missed customary details. I also thank the help #ffmpeg-devel that made my patch (3rd) simpler than I originally thought. Regards, Lluís. -- (Escriu-me xifrat si saps PGP / Write ciphered if you know PGP) PGP key 7CBD1DA5 - https://emailselfdefense.fsf.org/
>From ac005288e1b8493dcf7457171820dcf1a2fa03ca Mon Sep 17 00:00:00 2001 From: Cosmin Gorgovan <cos...@linux-geek.org> Date: Thu, 20 Aug 2020 21:05:23 +0100 Subject: [PATCH 1/3] libavcodec/mmaldec: enable MJPEG decoding --- configure | 1 + libavcodec/allcodecs.c | 1 + libavcodec/mmaldec.c | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/configure b/configure index a76c2ec4ae..048bedb589 100755 --- a/configure +++ b/configure @@ -3105,6 +3105,7 @@ hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" hevc_v4l2m2m_decoder_select="hevc_mp4toannexb_bsf" hevc_v4l2m2m_encoder_deps="v4l2_m2m hevc_v4l2_m2m" mjpeg_cuvid_decoder_deps="cuvid" +mjpeg_mmal_decoder_deps="mmal" mjpeg_qsv_decoder_select="qsvdec" mjpeg_qsv_encoder_deps="libmfx" mjpeg_qsv_encoder_select="qsvenc" diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 16ec182a52..8d1908c6d5 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -187,6 +187,7 @@ extern AVCodec ff_mdec_decoder; extern AVCodec ff_mimic_decoder; extern AVCodec ff_mjpeg_encoder; extern AVCodec ff_mjpeg_decoder; +extern AVCodec ff_mjpeg_mmal_decoder; extern AVCodec ff_mjpegb_decoder; extern AVCodec ff_mmvideo_decoder; extern AVCodec ff_mobiclip_decoder; diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c index cb15ac072a..df14b9fc95 100644 --- a/libavcodec/mmaldec.c +++ b/libavcodec/mmaldec.c @@ -375,6 +375,9 @@ static av_cold int ffmmal_init_decoder(AVCodecContext *avctx) format_in = decoder->input[0]->format; format_in->type = MMAL_ES_TYPE_VIDEO; switch (avctx->codec_id) { + case AV_CODEC_ID_MJPEG: + format_in->encoding = MMAL_ENCODING_MJPEG; + break; case AV_CODEC_ID_MPEG2VIDEO: format_in->encoding = MMAL_ENCODING_MP2V; break; @@ -851,6 +854,7 @@ static const AVOption options[]={ }; FFMMAL_DEC(h264, AV_CODEC_ID_H264) +FFMMAL_DEC(mjpeg, AV_CODEC_ID_MJPEG) FFMMAL_DEC(mpeg2, AV_CODEC_ID_MPEG2VIDEO) FFMMAL_DEC(mpeg4, AV_CODEC_ID_MPEG4) FFMMAL_DEC(vc1, AV_CODEC_ID_VC1) -- 2.29.2
>From 62a2f1e7194405e004de9c2f0386b33c4b07446e Mon Sep 17 00:00:00 2001 From: Cosmin Gorgovan <cos...@linux-geek.org> Date: Thu, 20 Aug 2020 21:11:49 +0100 Subject: [PATCH 2/3] libavcodec/mmaldec: continue after receiving EOS without having sent one The previous logic in mmaldec was causing the MMAL MJPEG decoder to stop if it received an invalid frame - which happened to be the first frame received from a UVC camera via V4L2 in my application --- libavcodec/mmaldec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c index df14b9fc95..4dfaacbb41 100644 --- a/libavcodec/mmaldec.c +++ b/libavcodec/mmaldec.c @@ -711,9 +711,13 @@ static int ffmmal_read_frame(AVCodecContext *avctx, AVFrame *frame, int *got_fra goto done; } - ctx->eos_received |= !!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS); - if (ctx->eos_received) + int eos = !!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS); + if (eos) { + if (ctx->eos_sent) { + ctx->eos_received = 1; + } goto done; + } if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) { MMAL_COMPONENT_T *decoder = ctx->decoder; -- 2.29.2
>From 6ae87ea2012444ff52dcff36718d27fb9262b14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Batlle=20i=20Rossell?= <vi...@viric.name> Date: Wed, 10 Feb 2021 22:58:17 +0100 Subject: [PATCH 3/3] mmaldec with plain yuv420p without copy --- libavcodec/mmaldec.c | 48 ++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c index 4dfaacbb41..097b990f92 100644 --- a/libavcodec/mmaldec.c +++ b/libavcodec/mmaldec.c @@ -119,10 +119,11 @@ static void ffmmal_release_frame(void *opaque, uint8_t *data) // Setup frame with a new reference to buffer. The buffer must have been // allocated from the given pool. -static int ffmmal_set_ref(AVFrame *frame, FFPoolRef *pool, - MMAL_BUFFER_HEADER_T *buffer) +static int ffmmal_set_ref(AVCodecContext *avctx, AVFrame *frame, + FFPoolRef *pool, MMAL_BUFFER_HEADER_T *buffer) { FFBufferRef *ref = av_mallocz(sizeof(*ref)); + if (!ref) return AVERROR(ENOMEM); @@ -140,8 +141,19 @@ static int ffmmal_set_ref(AVFrame *frame, FFPoolRef *pool, atomic_fetch_add_explicit(&ref->pool->refcount, 1, memory_order_relaxed); mmal_buffer_header_acquire(buffer); - frame->format = AV_PIX_FMT_MMAL; - frame->data[3] = (uint8_t *)ref->buffer; + frame->format = avctx->pix_fmt; + + if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { + int w = FFALIGN(avctx->width, 32); + int h = FFALIGN(avctx->height, 16); + + av_image_fill_arrays(frame->data, frame->linesize, + buffer->data + buffer->type->video.offset[0], + avctx->pix_fmt, w, h, 1); + } else { + frame->data[3] = (uint8_t *)ref->buffer; + } + return 0; } @@ -633,30 +645,14 @@ static int ffmal_copy_frame(AVCodecContext *avctx, AVFrame *frame, frame->interlaced_frame = ctx->interlaced_frame; frame->top_field_first = ctx->top_field_first; - if (avctx->pix_fmt == AV_PIX_FMT_MMAL) { - if (!ctx->pool_out) - return AVERROR_UNKNOWN; // format change code failed with OOM previously - - if ((ret = ff_decode_frame_props(avctx, frame)) < 0) - goto done; - - if ((ret = ffmmal_set_ref(frame, ctx->pool_out, buffer)) < 0) - goto done; - } else { - int w = FFALIGN(avctx->width, 32); - int h = FFALIGN(avctx->height, 16); - uint8_t *src[4]; - int linesize[4]; + if (!ctx->pool_out) + return AVERROR_UNKNOWN; // format change code failed with OOM previously - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - goto done; + if ((ret = ff_decode_frame_props(avctx, frame)) < 0) + goto done; - av_image_fill_arrays(src, linesize, - buffer->data + buffer->type->video.offset[0], - avctx->pix_fmt, w, h, 1); - av_image_copy(frame->data, frame->linesize, src, linesize, - avctx->pix_fmt, avctx->width, avctx->height); - } + if ((ret = ffmmal_set_ref(avctx, frame, ctx->pool_out, buffer)) < 0) + goto done; frame->pts = buffer->pts == MMAL_TIME_UNKNOWN ? AV_NOPTS_VALUE : buffer->pts; #if FF_API_PKT_PTS -- 2.29.2
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".