diff --git a/package/ffmpeg/0017-FFmpeg-omxdec-add-mirror-rotation-and-crop-option.patch b/package/ffmpeg/0017-FFmpeg-omxdec-add-mirror-rotation-and-crop-option.patch new file mode 100644 index 00000000..109b3b1c --- /dev/null +++ b/package/ffmpeg/0017-FFmpeg-omxdec-add-mirror-rotation-and-crop-option.patch @@ -0,0 +1,265 @@ +From 0c7df7e92eb46143fabeefd42af3023e6b7fc53f Mon Sep 17 00:00:00 2001 +From: "arvin.zhu" +Date: Fri, 21 Oct 2022 10:39:31 +0800 +Subject: [PATCH] FFmpeg:omxdec: add mirror rotation and crop option + +add mirror rotation and crop option for mjpeg_omx decoder + +Signed-off-by: arvin.zhu +--- + libavcodec/omxdec.c | 181 +++++++++++++++++++++++++++++++++++--------- + 1 file changed, 146 insertions(+), 35 deletions(-) + +diff --git a/libavcodec/omxdec.c b/libavcodec/omxdec.c +index 87e5a1a..b4a7c96 100755 +--- a/libavcodec/omxdec.c ++++ b/libavcodec/omxdec.c +@@ -276,6 +276,15 @@ typedef struct OMXCodecContext { + + OMX_U32 scale_width; + OMX_U32 scale_height; ++ OMX_U32 rotation; ++ OMX_U32 mirror; ++ char *crop_expr; ++ struct { ++ int x; ++ int y; ++ int w; ++ int h; ++ } crop; + + int input_zerocopy; + int profile; +@@ -359,7 +368,6 @@ static OMX_ERRORTYPE event_handler(OMX_HANDLETYPE component, OMX_PTR app_data, O + av_log(s->avctx, AV_LOG_ERROR, "err %d\n",err); + return AVERROR_UNKNOWN; + } +- + for (i = 0; i < video_port_params.nPorts; i++) { + int port = video_port_params.nStartPortNumber + i; + OMX_PARAM_PORTDEFINITIONTYPE port_params = { 0 }; +@@ -571,7 +579,7 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role) + out_port_params.format.video.nBitrate = avctx->bit_rate; + out_port_params.format.video.xFramerate = in_port_params.format.video.xFramerate; + out_port_params.format.video.bFlagErrorConcealment = OMX_FALSE; +- av_log(avctx, AV_LOG_VERBOSE, "OMX setting pixel_format:%s\n", s->pixel_format); ++ + if (avctx->codec->id == AV_CODEC_ID_MPEG4) + out_port_params.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4; + else if (avctx->codec->id == AV_CODEC_ID_H264) { +@@ -580,12 +588,12 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role) + 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){ ++ else if (avctx->codec->id == AV_CODEC_ID_MJPEG) { + out_port_params.format.video.eCompressionFormat = OMX_VIDEO_CodingMJPEG; + + /* Set Scale config setting*/ + if (s->scale_width || s->scale_height) { +- av_log(avctx, AV_LOG_TRACE, "mjpeg decoder: scaling width: %ld scaling height: %ld .\n", s->scale_width, s->scale_height); ++ av_log(avctx, AV_LOG_TRACE, "mjpeg decoder: scaling width: %d scaling height: %d .\n", s->scale_width, s->scale_height); + OMX_CONFIG_SCALEFACTORTYPE ScaleConfig; + INIT_STRUCT(ScaleConfig); + ScaleConfig.nPortIndex = 1; +@@ -599,38 +607,138 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role) + out_port_params.format.video.nFrameHeight = avctx->height; + } + +- switch (av_get_pix_fmt(s->pixel_format)) { +- case AV_PIX_FMT_NV12: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; +- break; +- case AV_PIX_FMT_NV21: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYVU420SemiPlanar; +- break; +- case AV_PIX_FMT_YUV420P: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; +- break; +- case AV_PIX_FMT_NV16: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV422SemiPlanar; +- break; +- case AV_PIX_FMT_YUV422P: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV422Planar; +- break; +- case AV_PIX_FMT_YUYV422: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYCbYCr; +- break; +- case AV_PIX_FMT_YVYU422: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYCrYCb; +- break; +- case AV_PIX_FMT_UYVY422: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatCbYCrY; +- break; +- case AV_PIX_FMT_YUV444P: +- out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV444Planar; +- break; +- default: ++ /* Set pixel format to decoder output*/ ++ if (s->pixel_format) { ++ switch (av_get_pix_fmt(s->pixel_format)) { ++ case AV_PIX_FMT_NV12: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; ++ break; ++ case AV_PIX_FMT_NV21: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYVU420SemiPlanar; ++ break; ++ case AV_PIX_FMT_YUV420P: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; ++ break; ++ case AV_PIX_FMT_NV16: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV422SemiPlanar; ++ break; ++ case AV_PIX_FMT_YUV422P: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV422Planar; ++ break; ++ case AV_PIX_FMT_YUYV422: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYCbYCr; ++ break; ++ case AV_PIX_FMT_YVYU422: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYCrYCb; ++ break; ++ case AV_PIX_FMT_UYVY422: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatCbYCrY; ++ break; ++ case AV_PIX_FMT_YUV444P: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV444Planar; ++ break; ++ default: ++ return AVERROR_OPTION_NOT_FOUND; ++ } ++ av_log(avctx, AV_LOG_VERBOSE, "OMX setting pixel_format:%s\n", s->pixel_format); ++ } else { ++ switch (avctx->pix_fmt) { ++ case AV_PIX_FMT_YUVJ420P: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; ++ break; ++ case AV_PIX_FMT_YUVJ422P: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV422Planar; ++ break; ++ case AV_PIX_FMT_YUVJ444P: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV444Planar; ++ break; ++ default: ++ out_port_params.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; ++ break; ++ } ++ } ++ ++ /* Set Mirror config setting*/ ++ if (s->mirror) { ++ if (s->pixel_format || s->scale_width || s->scale_height || s->rotation) { ++ av_log(avctx, AV_LOG_ERROR, "Mirror cannot work with other option together.\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ av_log(avctx, AV_LOG_TRACE, "mjpeg decoder: mirror\n"); ++ OMX_CONFIG_MIRRORTYPE MirrorConfig; ++ INIT_STRUCT(MirrorConfig); ++ MirrorConfig.nPortIndex = 1; ++ OMX_GetConfig(s->handle, OMX_IndexConfigCommonMirror, &MirrorConfig); ++ MirrorConfig.eMirror = s->mirror; ++ OMX_SetConfig(s->handle, OMX_IndexConfigCommonMirror, &MirrorConfig); ++ } ++ ++ /* Set Rotation config setting*/ ++ if (s->rotation) { ++ if (s->pixel_format || s->scale_width || s->scale_height || s->mirror) { ++ av_log(avctx, AV_LOG_ERROR, "Rotation cannot work with other option together.\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ av_log(avctx, AV_LOG_TRACE, "mjpeg decoder: rotation\n"); ++ OMX_CONFIG_ROTATIONTYPE RotatConfig; ++ INIT_STRUCT(RotatConfig); ++ RotatConfig.nPortIndex = 1; ++ OMX_GetConfig(s->handle, OMX_IndexConfigCommonRotate, &RotatConfig); ++ switch (s->rotation) { ++ case 1: ++ RotatConfig.nRotation = 90; ++ break; ++ case 2: ++ RotatConfig.nRotation = 180; ++ break; ++ case 3: ++ RotatConfig.nRotation = 270; ++ break; ++ default: ++ RotatConfig.nRotation = 0; ++ break; ++ } ++ OMX_SetConfig(s->handle, OMX_IndexConfigCommonRotate, &RotatConfig); ++ } ++ ++ /* Set Roi config setting*/ ++ if (s->crop_expr && sscanf(s->crop_expr, "%d,%d,%d,%d", ++ &s->crop.x, &s->crop.y, ++ &s->crop.w, &s->crop.h) != 4) { ++ av_log(avctx, AV_LOG_ERROR, "Invalid cropping expressions.\n"); + return AVERROR_OPTION_NOT_FOUND; + } ++ ++ if (s->crop.w && s->crop.h) { ++ if (s->pixel_format || s->scale_width || s->scale_height || s->mirror || s->rotation) { ++ av_log(avctx, AV_LOG_ERROR, "Crop cannot work with other option together.\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ if ((s->crop.x < 0) || (s->crop.x > (avctx->width - s->crop.w)) || ++ (s->crop.y < 0) || (s->crop.y > (avctx->height - s->crop.h)) || ++ (s->crop.w < 16) || (s->crop.w > (avctx->width - s->crop.x)) || ++ (s->crop.h < 16) || (s->crop.h > (avctx->height - s->crop.y))) { ++ av_log(avctx, AV_LOG_ERROR, "Invalid cropping range.\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ if (s->crop.w % 16 != 0 || s->crop.h % 16 != 0) { ++ av_log(avctx, AV_LOG_ERROR, "The width/height must be an integer multiple of 16\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ OMX_CONFIG_RECTTYPE RectConfig; ++ INIT_STRUCT(RectConfig); ++ RectConfig.nPortIndex = 1; ++ OMX_GetConfig(s->handle, OMX_IndexConfigCommonOutputCrop, &RectConfig); ++ RectConfig.nLeft = s->crop.x; ++ RectConfig.nTop = s->crop.y; ++ RectConfig.nWidth = s->crop.w; ++ RectConfig.nHeight = s->crop.h; ++ OMX_SetConfig(s->handle, OMX_IndexConfigCommonOutputCrop, &RectConfig); ++ av_log(avctx, AV_LOG_ERROR, "mjpeg decoder:roi x: %d y: %d w: %d h: %d .\n", s->crop.x, s->crop.y, s->crop.w, s->crop.h); ++ } + } ++ + if (avctx->codec->id == AV_CODEC_ID_H264 || avctx->codec->id == AV_CODEC_ID_HEVC) { + /* Set Scale config setting*/ + if ((s->scale_width != 0) && ((s->scale_width < avctx->width/8) || +@@ -675,6 +783,7 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role) + s->done_out_buffers = av_mallocz(sizeof(OMX_BUFFERHEADERTYPE*) * s->num_out_buffers); + if (!s->in_buffer_headers || !s->free_in_buffers || !s->out_buffer_headers || !s->done_out_buffers) + return AVERROR(ENOMEM); ++ + for (i = 0; i < s->num_in_buffers && err == OMX_ErrorNone; i++) { + if (s->input_zerocopy) + err = OMX_UseBuffer(s->handle, &s->in_buffer_headers[i], s->in_port, s, in_port_params.nBufferSize, NULL); +@@ -699,7 +808,6 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role) + av_log(avctx, AV_LOG_ERROR, "Didn't get OMX_StateExecuting\n"); + return AVERROR_UNKNOWN; + } +- + for (i = 0; i < s->num_out_buffers && err == OMX_ErrorNone; i++) + err = OMX_FillThisBuffer(s->handle, s->out_buffer_headers[i]); + if (err != OMX_ErrorNone) { +@@ -1055,9 +1163,12 @@ static const AVOption options_mjpeg[] = { + { "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 }, + { "zerocopy", "Try to avoid copying input frames if possible", OFFSET(input_zerocopy), AV_OPT_TYPE_INT, { .i64 = CONFIG_OMX_RPI }, 0, 1, VD }, +- { "omx_pix_fmt", "Set the decoding pixel format for mjpeg_omx decoder. The following formats are supported: yuv420p, nv12, nv21, nv16, yuv422p, yuyv422, yvyu422, uyvy422, yuv444p.", OFFSET(pixel_format), AV_OPT_TYPE_STRING, { .str = "yuv420p" }, 0, 0, VD }, ++ { "omx_pix_fmt", "Set the decoding pixel format for mjpeg_omx decoder. The following formats are supported: yuv420p, nv12, nv21, nv16, yuv422p, yuyv422, yvyu422, uyvy422, yuv444p.", OFFSET(pixel_format), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, + { "scale_width", "Set the scaling width for omx (Only zoom out is support, Horizontal downscale: 0(none), 1(1/2), 2(1/4), 3(1/8)) and minimum 1/8)", OFFSET(scale_width), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, VD }, + { "scale_height", "Set the scaling height for omx (Only zoom out is support, Vertical downscale: 0(none), 1(1/2), 2(1/4), 3(1/8)) and minimum 1/8)", OFFSET(scale_height), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, VD }, ++ { "mirror", "mirror 0(none), 1(V), 2(H) or 3(VH), cannot be set at the same time as pixel format conversion, rotation and crop", OFFSET(mirror), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, VD }, ++ { "rotation", "rotation 0(0), 1(90), 2(180) or 3(270), cannot be set at the same time as pixel format conversion, mirror and crop", OFFSET(rotation), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, VD }, ++ { "crop", "crop ,,,: crop coord and width/height(from left/top, must be an integer multiple of 16), cannot be set at the same time as pixel format conversion, mirror and rotation", OFFSET(crop_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, + { NULL }, + }; + +-- +2.17.1 +