|
@@ -0,0 +1,324 @@
|
|
|
+From 5102c406a361cba201b9d5eb1301937a39308c11 Mon Sep 17 00:00:00 2001
|
|
|
+From: sw.multimedia <sw.multimedia@starfivetech.com>
|
|
|
+Date: Fri, 4 Mar 2022 15:32:52 +0800
|
|
|
+Subject: [PATCH] add mjpeg decoder support and fix default big framerate issue
|
|
|
+
|
|
|
+---
|
|
|
+ configure | 1 +
|
|
|
+ libavcodec/allcodecs.c | 1 +
|
|
|
+ libavcodec/omx.c | 4 ++--
|
|
|
+ libavcodec/omxdec.c | 54 ++++++++++++++++++++++++++++++++----------
|
|
|
+ libavformat/utils.c | 21 +++++++++++-----
|
|
|
+ 5 files changed, 61 insertions(+), 20 deletions(-)
|
|
|
+
|
|
|
+diff --git a/configure b/configure
|
|
|
+index 5523c59..0e91768 100755
|
|
|
+--- a/configure
|
|
|
++++ b/configure
|
|
|
+@@ -3065,6 +3065,7 @@ h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf"
|
|
|
+ h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m"
|
|
|
+ hevc_omx_encoder_deps="omx"
|
|
|
+ hevc_omx_decoder_deps="omx"
|
|
|
++mjpeg_omx_decoder_deps="omx"
|
|
|
+ hevc_amf_encoder_deps="amf"
|
|
|
+ hevc_cuvid_decoder_deps="cuvid"
|
|
|
+ hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf"
|
|
|
+diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
|
|
|
+index b9db275..73f86fa 100644
|
|
|
+--- a/libavcodec/allcodecs.c
|
|
|
++++ b/libavcodec/allcodecs.c
|
|
|
+@@ -791,6 +791,7 @@ extern AVCodec ff_libkvazaar_encoder;
|
|
|
+ extern AVCodec ff_mjpeg_cuvid_decoder;
|
|
|
+ extern AVCodec ff_mjpeg_qsv_encoder;
|
|
|
+ extern AVCodec ff_mjpeg_qsv_decoder;
|
|
|
++extern AVCodec ff_mjpeg_omx_decoder;
|
|
|
+ extern AVCodec ff_mjpeg_vaapi_encoder;
|
|
|
+ extern AVCodec ff_mpeg1_cuvid_decoder;
|
|
|
+ extern AVCodec ff_mpeg2_cuvid_decoder;
|
|
|
+diff --git a/libavcodec/omx.c b/libavcodec/omx.c
|
|
|
+index e3140f1..a05183a 100644
|
|
|
+--- a/libavcodec/omx.c
|
|
|
++++ b/libavcodec/omx.c
|
|
|
+@@ -475,9 +475,9 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role)
|
|
|
+ in_port_params.format.video.nFrameWidth = avctx->width;
|
|
|
+ in_port_params.format.video.nFrameHeight = avctx->height;
|
|
|
+ if (avctx->framerate.den > 0 && avctx->framerate.num > 0)
|
|
|
+- in_port_params.format.video.xFramerate = (1LL << 16) * avctx->framerate.num / avctx->framerate.den;
|
|
|
++ in_port_params.format.video.xFramerate = avctx->framerate.num / avctx->framerate.den;
|
|
|
+ else
|
|
|
+- in_port_params.format.video.xFramerate = (1LL << 16) * avctx->time_base.den / avctx->time_base.num;
|
|
|
++ in_port_params.format.video.xFramerate = avctx->time_base.den / avctx->time_base.num;
|
|
|
+
|
|
|
+ err = OMX_SetParameter(s->handle, OMX_IndexParamPortDefinition, &in_port_params);
|
|
|
+ CHECK(err);
|
|
|
+diff --git a/libavcodec/omxdec.c b/libavcodec/omxdec.c
|
|
|
+index f5da60d..d055d19 100755
|
|
|
+--- a/libavcodec/omxdec.c
|
|
|
++++ b/libavcodec/omxdec.c
|
|
|
+@@ -107,6 +107,7 @@ static const struct {
|
|
|
+ { OMX_COLOR_FormatYUV420Planar, AV_PIX_FMT_YUV420P },
|
|
|
+ { OMX_COLOR_FormatYUV420SemiPlanar, AV_PIX_FMT_NV12 },
|
|
|
+ { OMX_COLOR_FormatYUV420PackedSemiPlanar, AV_PIX_FMT_NV21 },
|
|
|
++ { OMX_COLOR_FormatYUV444Interleaved, AV_PIX_FMT_YUV444P },
|
|
|
+ { 0 }
|
|
|
+ };
|
|
|
+
|
|
|
+@@ -366,7 +367,7 @@ static OMX_ERRORTYPE event_handler(OMX_HANDLETYPE component, OMX_PTR app_data, O
|
|
|
+ dec_out_width = out_port_params.format.video.nFrameWidth;
|
|
|
+ dec_out_height = out_port_params.format.video.nFrameHeight;
|
|
|
+ dec_pix_fmt = out_port_params.format.video.eColorFormat;
|
|
|
+-
|
|
|
++ av_log(s->avctx, AV_LOG_VERBOSE, "w:%d, h:%d, fmt:%d\n", dec_out_width, dec_out_height, dec_pix_fmt);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+@@ -384,7 +385,6 @@ static OMX_ERRORTYPE event_handler(OMX_HANDLETYPE component, OMX_PTR app_data, O
|
|
|
+ static OMX_ERRORTYPE empty_buffer_done(OMX_HANDLETYPE component, OMX_PTR app_data,
|
|
|
+ OMX_BUFFERHEADERTYPE *buffer)
|
|
|
+ {
|
|
|
+-
|
|
|
+ OMXCodecContext *s = app_data;
|
|
|
+ if (s->input_zerocopy) {
|
|
|
+ if (buffer->pAppPrivate) {
|
|
|
+@@ -536,9 +536,9 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role)
|
|
|
+ in_port_params.format.video.nFrameHeight = avctx->height;
|
|
|
+
|
|
|
+ if (avctx->framerate.den > 0 && avctx->framerate.num > 0)
|
|
|
+- in_port_params.format.video.xFramerate = (1LL << 16) * avctx->framerate.num / avctx->framerate.den;
|
|
|
++ in_port_params.format.video.xFramerate = avctx->framerate.num / avctx->framerate.den;
|
|
|
+ else
|
|
|
+- in_port_params.format.video.xFramerate = (1LL << 16) * avctx->time_base.den / avctx->time_base.num;
|
|
|
++ in_port_params.format.video.xFramerate = avctx->time_base.den / avctx->time_base.num;
|
|
|
+
|
|
|
+ err = OMX_SetParameter(s->handle, OMX_IndexParamPortDefinition, &in_port_params);
|
|
|
+ CHECK(err);
|
|
|
+@@ -567,6 +567,8 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role)
|
|
|
+ out_port_params.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
|
|
|
+ else if (avctx->codec->id == AV_CODEC_ID_HEVC)
|
|
|
+ out_port_params.format.video.eCompressionFormat = OMX_VIDEO_CodingHEVC;
|
|
|
++ else if (avctx->codec->id == AV_CODEC_ID_MJPEG)
|
|
|
++ out_port_params.format.video.eCompressionFormat = OMX_VIDEO_CodingMJPEG;
|
|
|
+
|
|
|
+ err = OMX_SetParameter(s->handle, OMX_IndexParamPortDefinition, &out_port_params);
|
|
|
+ CHECK(err);
|
|
|
+@@ -702,11 +704,13 @@ static av_cold int omx_decode_init(AVCodecContext *avctx)
|
|
|
+ case AV_CODEC_ID_HEVC:
|
|
|
+ role = "video_decoder.hevc";
|
|
|
+ break;
|
|
|
++ case AV_CODEC_ID_MJPEG:
|
|
|
++ role = "video_decoder.mjpeg";
|
|
|
++ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return AVERROR(ENOSYS);
|
|
|
+ }
|
|
|
+-
|
|
|
+ if ((ret = find_component(s->omx_context, avctx, role, s->component_name, sizeof(s->component_name))) < 0)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+@@ -764,14 +768,15 @@ static int omx_decode_frame(AVCodecContext *avctx, void *data,
|
|
|
+ buffer->pAppPrivate = avctx->priv_data;
|
|
|
+ buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
|
|
|
+
|
|
|
+-
|
|
|
+ err = OMX_EmptyThisBuffer(s->handle, buffer);
|
|
|
+ if (err != OMX_ErrorNone) {
|
|
|
+ append_buffer(&s->input_mutex, &s->input_cond, &s->num_free_in_buffers, s->free_in_buffers, buffer);
|
|
|
+ av_log(avctx, AV_LOG_ERROR, "OMX_EmptyThisBuffer failed: %x\n", err);
|
|
|
+ return AVERROR_UNKNOWN;
|
|
|
+ }
|
|
|
++
|
|
|
+ } else if (!s->eos_sent) {
|
|
|
++
|
|
|
+
|
|
|
+ buffer = get_buffer(&s->input_mutex, &s->input_cond,
|
|
|
+ &s->num_free_in_buffers, s->free_in_buffers, 1);
|
|
|
+@@ -784,7 +789,6 @@ static int omx_decode_frame(AVCodecContext *avctx, void *data,
|
|
|
+ buffer->nFilledLen = 0;
|
|
|
+ buffer->nFlags = OMX_BUFFERFLAG_EOS;
|
|
|
+ buffer->pAppPrivate = buffer->pOutputPortPrivate = NULL;
|
|
|
+-
|
|
|
+ err = OMX_EmptyThisBuffer(s->handle, buffer);
|
|
|
+ if (err != OMX_ErrorNone) {
|
|
|
+ append_buffer(&s->input_mutex, &s->input_cond, &s->num_free_in_buffers, s->free_in_buffers, buffer);
|
|
|
+@@ -793,7 +797,7 @@ static int omx_decode_frame(AVCodecContext *avctx, void *data,
|
|
|
+ }
|
|
|
+ s->eos_sent = 1;
|
|
|
+ }
|
|
|
+-
|
|
|
++
|
|
|
+ while (!*got_packet && ret == 0 && !s->got_eos) {
|
|
|
+ // If not flushing, just poll the queue if there's finished packets.
|
|
|
+ // If flushing, do a blocking wait until we either get a completed
|
|
|
+@@ -804,11 +808,13 @@ static int omx_decode_frame(AVCodecContext *avctx, void *data,
|
|
|
+ !pkt || had_partial);
|
|
|
+
|
|
|
+ if (!buffer) {
|
|
|
+- /*eos is sent wait for vpu evnet_bufferflag to get all frames*/
|
|
|
+- if(s->eos_sent && !evnet_bufferflag){
|
|
|
++
|
|
|
++ /*eos is sent wait for vpu evnet_bufferflag to get all frames
|
|
|
++ mjpeg: sent a frame, then wait for a decoder frame
|
|
|
++ */
|
|
|
++ if((s->eos_sent && !evnet_bufferflag) || (avctx->codec_id == AV_CODEC_ID_MJPEG )) {
|
|
|
+ continue;
|
|
|
+- }
|
|
|
+- break;
|
|
|
++ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!buffer->nFilledLen){
|
|
|
+@@ -818,6 +824,7 @@ static int omx_decode_frame(AVCodecContext *avctx, void *data,
|
|
|
+ avctx->width = dec_out_width;
|
|
|
+ avctx->height = dec_out_height;
|
|
|
+ avctx->pix_fmt = omx_map_color_format(avctx, dec_pix_fmt);
|
|
|
++
|
|
|
+ s->stride = avctx->width;
|
|
|
+ s->plane_size = avctx->height;
|
|
|
+
|
|
|
+@@ -863,6 +870,8 @@ static av_cold int omx_decode_end(AVCodecContext *avctx)
|
|
|
+ #define OFFSET(x) offsetof(OMXCodecContext, x)
|
|
|
+ #define VDE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM
|
|
|
+ #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
|
|
|
++#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
|
|
|
++
|
|
|
+ static const AVOption options[] = {
|
|
|
+ { "omx_libname", "OpenMAX library name", OFFSET(libname), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VDE },
|
|
|
+ { "omx_libprefix", "OpenMAX library prefix", OFFSET(libprefix), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VDE },
|
|
|
+@@ -944,4 +953,25 @@ AVCodec ff_hevc_omx_decoder = {
|
|
|
+ .priv_class = &omx_hevcdec_class,
|
|
|
+ };
|
|
|
+
|
|
|
++static const AVClass omx_mjpegdec_class = {
|
|
|
++ .class_name = "mjpeg_omx",
|
|
|
++ .item_name = av_default_item_name,
|
|
|
++ .version = LIBAVUTIL_VERSION_INT,
|
|
|
++};
|
|
|
++AVCodec ff_mjpeg_omx_decoder = {
|
|
|
++ .name = "mjpeg_omx",
|
|
|
++ .long_name = NULL_IF_CONFIG_SMALL("OpenMAX IL mjpeg video decoder"),
|
|
|
++ .type = AVMEDIA_TYPE_VIDEO,
|
|
|
++ .id = AV_CODEC_ID_MJPEG,
|
|
|
++ .priv_data_size = sizeof(OMXCodecContext),
|
|
|
++ .init = omx_decode_init,
|
|
|
++ .decode = omx_decode_frame,
|
|
|
++ .close = omx_decode_end,
|
|
|
++ .capabilities = AV_CODEC_CAP_DR1,
|
|
|
++ .max_lowres = 3,
|
|
|
++ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
|
|
|
++ .priv_class = &omx_mjpegdec_class,
|
|
|
++};
|
|
|
++
|
|
|
++
|
|
|
+
|
|
|
+diff --git a/libavformat/utils.c b/libavformat/utils.c
|
|
|
+index 11fdc44..1aaf3aa 100644
|
|
|
+--- a/libavformat/utils.c
|
|
|
++++ b/libavformat/utils.c
|
|
|
+@@ -218,6 +218,14 @@ static const AVCodec *find_probe_decoder(AVFormatContext *s, const AVStream *st,
|
|
|
+ return avcodec_find_decoder_by_name("hevc");
|
|
|
+ #endif
|
|
|
+
|
|
|
++#if CONFIG_MJPEG_DECODER
|
|
|
++ /* Other parts of the code assume this decoder to be used for mjpeg,
|
|
|
++ * so force it if possible. */
|
|
|
++ if (codec_id == AV_CODEC_ID_MJPEG)
|
|
|
++ return avcodec_find_decoder_by_name("mjpeg");
|
|
|
++#endif
|
|
|
++
|
|
|
++
|
|
|
+ codec = find_decoder(s, st, codec_id);
|
|
|
+ if (!codec)
|
|
|
+ return NULL;
|
|
|
+@@ -3047,7 +3055,6 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr)
|
|
|
+ case AVMEDIA_TYPE_DATA:
|
|
|
+ if (avctx->codec_id == AV_CODEC_ID_NONE) return 1;
|
|
|
+ }
|
|
|
+-
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -3085,6 +3092,7 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st,
|
|
|
+ av_dict_set(options ? options : &thread_opt, "threads", "1", 0);
|
|
|
+ if (s->codec_whitelist)
|
|
|
+ av_dict_set(options ? options : &thread_opt, "codec_whitelist", s->codec_whitelist, 0);
|
|
|
++
|
|
|
+ ret = avcodec_open2(avctx, codec, options ? options : &thread_opt);
|
|
|
+ if (!options)
|
|
|
+ av_dict_free(&thread_opt);
|
|
|
+@@ -3095,7 +3103,7 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st,
|
|
|
+ st->info->found_decoder = 1;
|
|
|
+ } else if (!st->info->found_decoder)
|
|
|
+ st->info->found_decoder = 1;
|
|
|
+-
|
|
|
++
|
|
|
+ if (st->info->found_decoder < 0) {
|
|
|
+ ret = -1;
|
|
|
+ goto fail;
|
|
|
+@@ -3106,7 +3114,7 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st,
|
|
|
+ skip_frame = avctx->skip_frame;
|
|
|
+ avctx->skip_frame = AVDISCARD_ALL;
|
|
|
+ }
|
|
|
+-
|
|
|
++
|
|
|
+ while ((pkt.size > 0 || (!pkt.data && got_picture)) &&
|
|
|
+ ret >= 0 &&
|
|
|
+ (!has_codec_parameters(st, NULL) || !has_decode_delay_been_guessed(st) ||
|
|
|
+@@ -3751,7 +3759,6 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
+ av_log(ic, AV_LOG_DEBUG, "interrupted\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+-
|
|
|
+ /* check if one codec still needs to be handled */
|
|
|
+ for (i = 0; i < ic->nb_streams; i++) {
|
|
|
+ int fps_analyze_framecount = 20;
|
|
|
+@@ -3850,6 +3857,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
+ pkt = &pkt1;
|
|
|
+ }
|
|
|
+
|
|
|
++
|
|
|
+ st = ic->streams[pkt->stream_index];
|
|
|
+ if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
|
|
|
+ read_size += pkt->size;
|
|
|
+@@ -3861,7 +3869,6 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
+ goto unref_then_goto_end;
|
|
|
+ st->internal->avctx_inited = 1;
|
|
|
+ }
|
|
|
+-
|
|
|
+ if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) {
|
|
|
+ /* check for non-increasing dts */
|
|
|
+ if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
|
|
|
+@@ -3901,6 +3908,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
+ st->info->fps_last_dts = pkt->dts;
|
|
|
+ st->info->fps_last_dts_idx = st->codec_info_nb_frames;
|
|
|
+ }
|
|
|
++
|
|
|
+ if (st->codec_info_nb_frames>1) {
|
|
|
+ int64_t t = 0;
|
|
|
+ int64_t limit;
|
|
|
+@@ -3949,6 +3957,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
+ goto unref_then_goto_end;
|
|
|
+ }
|
|
|
+
|
|
|
++
|
|
|
+ /* If still no information, we try to open the codec and to
|
|
|
+ * decompress the frame. We try to avoid that in most cases as
|
|
|
+ * it takes longer and uses more memory. For MPEG-4, we need to
|
|
|
+@@ -3961,13 +3970,13 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
+ try_decode_frame(ic, st, pkt,
|
|
|
+ (options && i < orig_nb_streams) ? &options[i] : NULL);
|
|
|
+
|
|
|
++
|
|
|
+ if (ic->flags & AVFMT_FLAG_NOBUFFER)
|
|
|
+ av_packet_unref(&pkt1);
|
|
|
+
|
|
|
+ st->codec_info_nb_frames++;
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+-
|
|
|
+ if (eof_reached) {
|
|
|
+ int stream_index;
|
|
|
+ for (stream_index = 0; stream_index < ic->nb_streams; stream_index++) {
|
|
|
+--
|
|
|
+2.17.1
|
|
|
+
|