Files
fml13v01-buildroot/package/ffmpeg/0017-FFmpeg-omxdec-add-mirror-rotation-and-crop-option.patch
arvin.zhu 47cfc8cd38 FFmpeg:omxdec: add mirror rotation and crop options
add mirror rotation and crop options

Signed-off-by: arvin.zhu <arvin.zhu@starfivetech.com>
2022-10-28 22:14:43 +08:00

266 lines
13 KiB
Diff

From 0c7df7e92eb46143fabeefd42af3023e6b7fc53f Mon Sep 17 00:00:00 2001
From: "arvin.zhu" <arvin.zhu@starfivetech.com>
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 <arvin.zhu@starfivetech.com>
---
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 <x>,<y>,<w>,<h>: 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