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