Files
mpp/utils/mpi_enc_utils.c
Herman Chen 16ba8b5820 [hal_h264e_vepu]: Fix stride parameter compatible
Fix stride definition to compatible to both pixel stride and byte
stride.

In MPI the stride is defined to byte stride. But vepu requires 8 pixel
aligned pixel stride.

So we add more code to adapt to both case and check 8 pixel alignment.

From opengles definition:

Stride means bytes in a row of pixels including padding. So an image
could be 510 pixels in width and rounded up to 512 pixels. The stride
would be 512 * bit depth of the image's format. You could also have
stride in pixels in which case the stride would be 512 pixels

Pitch is a little more vague, but typically could be interchangeable
with stride. Considering your reference is specifying in bytes, it's
likely safe to assume they're not measuring in pixels. So the reference
likely means the number of bytes in a row + padding, the only
alternative would be number of bytes without padding e.g. image width *
bit depth.

Change-Id: I20acf71e2a6bea2eb08b41fe7df531154ebef897
Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
2020-09-28 09:25:06 +08:00

677 lines
22 KiB
C

/*
* Copyright 2015 Rockchip Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define MODULE_TAG "mpi_enc_utils"
#include <string.h>
#include "mpp_mem.h"
#include "mpp_log.h"
#include "rk_mpi.h"
#include "utils.h"
#include "mpp_common.h"
#include "mpi_enc_utils.h"
#define MAX_FILE_NAME_LENGTH 256
RK_S32 mpi_enc_width_default_stride(RK_S32 width, MppFrameFormat fmt)
{
RK_S32 stride = 0;
switch (fmt & MPP_FRAME_FMT_MASK) {
case MPP_FMT_YUV420SP : {
stride = MPP_ALIGN(width, 8);
} break;
case MPP_FMT_YUV420P : {
/* NOTE: 420P need to align to 16 so chroma can align to 8 */
stride = MPP_ALIGN(width, 16);
} break;
case MPP_FMT_YUV422P:
case MPP_FMT_YUV422SP: {
/* NOTE: 422 need to align to 8 so chroma can align to 16 */
stride = MPP_ALIGN(width, 8);
} break;
case MPP_FMT_RGB565:
case MPP_FMT_BGR565:
case MPP_FMT_RGB555:
case MPP_FMT_BGR555:
case MPP_FMT_RGB444:
case MPP_FMT_BGR444:
case MPP_FMT_YUV422_YUYV :
case MPP_FMT_YUV422_YVYU :
case MPP_FMT_YUV422_UYVY :
case MPP_FMT_YUV422_VYUY : {
/* NOTE: for vepu limitation */
stride = MPP_ALIGN(width, 8) * 2;
} break;
case MPP_FMT_RGB888 :
case MPP_FMT_BGR888 : {
/* NOTE: for vepu limitation */
stride = MPP_ALIGN(width, 8) * 3;
} break;
case MPP_FMT_RGB101010 :
case MPP_FMT_BGR101010 :
case MPP_FMT_ARGB8888 :
case MPP_FMT_ABGR8888 :
case MPP_FMT_BGRA8888 :
case MPP_FMT_RGBA8888 : {
/* NOTE: for vepu limitation */
stride = MPP_ALIGN(width, 8) * 4;
} break;
default : {
mpp_err_f("do not support type %d\n", fmt);
} break;
}
return stride;
}
MpiEncTestArgs *mpi_enc_test_cmd_get(void)
{
MpiEncTestArgs *args = mpp_calloc(MpiEncTestArgs, 1);
return args;
}
MPP_RET mpi_enc_test_cmd_update_by_args(MpiEncTestArgs* cmd, int argc, char **argv)
{
const char *opt;
const char *next;
RK_S32 optindex = 1;
RK_S32 handleoptions = 1;
MPP_RET ret = MPP_NOK;
if ((argc < 2) || (cmd == NULL))
return ret;
/* parse options */
while (optindex < argc) {
opt = (const char*)argv[optindex++];
next = (const char*)argv[optindex];
if (handleoptions && opt[0] == '-' && opt[1] != '\0') {
if (opt[1] == '-') {
if (opt[2] != '\0') {
opt++;
} else {
handleoptions = 0;
continue;
}
}
opt++;
switch (*opt) {
case 'i' : {
if (next) {
size_t len = strnlen(next, MAX_FILE_NAME_LENGTH);
if (len) {
cmd->file_input = mpp_calloc(char, len + 1);
strcpy(cmd->file_input, next);
name_to_frame_format(cmd->file_input, &cmd->format);
}
} else {
mpp_err("input file is invalid\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'o' : {
if (next) {
size_t len = strnlen(next, MAX_FILE_NAME_LENGTH);
if (len) {
cmd->file_output = mpp_calloc(char, len + 1);
strcpy(cmd->file_output, next);
name_to_coding_type(cmd->file_output, &cmd->type);
}
} else {
mpp_log("output file is invalid\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'w' : {
if (next) {
cmd->width = atoi(next);
} else {
mpp_err("invalid input width\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'h' : {
if (!next)
goto PARSE_OPINIONS_OUT;
if ((*(opt + 1) != '\0') && !strncmp(opt, "help", 4)) {
goto PARSE_OPINIONS_OUT;
} else if (next) {
cmd->height = atoi(next);
}
} break;
case 'u' : {
if (next) {
cmd->hor_stride = atoi(next);
} else {
mpp_err("invalid input width\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'v' : {
if (next) {
cmd->ver_stride = atoi(next);
} else {
mpp_log("input height is invalid\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'f' : {
if (next) {
if (strstr(next, "x") || strstr(next, "X")) {
/* hex value with 0x prefix, use sscanf */
sscanf(next, "0x%x", &cmd->format);
} else if (strstr(next, "a") || strstr(next, "A") ||
strstr(next, "b") || strstr(next, "B") ||
strstr(next, "c") || strstr(next, "C") ||
strstr(next, "d") || strstr(next, "D") ||
strstr(next, "e") || strstr(next, "E") ||
strstr(next, "f") || strstr(next, "F")) {
/* hex value without 0x prefix, use sscanf */
sscanf(next, "%x", &cmd->format);
} else {
/* decimal value, use atoi */
cmd->format = (MppFrameFormat)atoi(next);
}
ret = (!MPP_FRAME_FMT_IS_LE(cmd->format)) && ((cmd->format >= MPP_FMT_YUV_BUTT && cmd->format < MPP_FRAME_FMT_RGB) ||
cmd->format >= MPP_FMT_RGB_BUTT);
}
if (!next || ret) {
mpp_err("invalid input format %d\n", cmd->format);
goto PARSE_OPINIONS_OUT;
}
} break;
case 't' : {
if (next) {
cmd->type = (MppCodingType)atoi(next);
ret = mpp_check_support_format(MPP_CTX_ENC, cmd->type);
}
if (!next || ret) {
mpp_err("invalid input coding type\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'n' : {
if (next) {
cmd->num_frames = atoi(next);
} else {
mpp_err("invalid input max number of frames\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'g' : {
RK_S32 cnt = 0;
if (next)
cnt = sscanf(next, "%d:%d:%d",
&cmd->gop_mode, &cmd->gop_len, &cmd->vi_len);
if (!cnt) {
mpp_err("invalid gop mode use -g gop_mode:gop_len:vi_len\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'b' : {
RK_S32 cnt = 0;
if (next)
cnt = sscanf(next, "%d:%d:%d:%d",
&cmd->bps_target, &cmd->bps_min, &cmd->bps_max,
&cmd->rc_mode);
if (!cnt) {
mpp_err("invalid bit rate usage -b bps_target:bps_min:bps_max:rc_mode\n");
mpp_err("rc_mode 0:vbr 1:cbr 2:avbr 3:cvbr 4:fixqp\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'r' : {
if (next) {
RK_S32 num = sscanf(next, "%d:%d:%d/%d:%d:%d",
&cmd->fps_in_num, &cmd->fps_in_den, &cmd->fps_in_flex,
&cmd->fps_out_num, &cmd->fps_out_den, &cmd->fps_out_flex);
switch (num) {
case 1 : {
cmd->fps_out_num = cmd->fps_in_num;
cmd->fps_out_den = cmd->fps_in_den = 1;
cmd->fps_out_flex = cmd->fps_in_flex = 0;
} break;
case 2 : {
cmd->fps_out_num = cmd->fps_in_num;
cmd->fps_out_den = cmd->fps_in_den;
cmd->fps_out_flex = cmd->fps_in_flex = 0;
} break;
case 3 : {
cmd->fps_out_num = cmd->fps_in_num;
cmd->fps_out_den = cmd->fps_in_den;
cmd->fps_out_flex = cmd->fps_in_flex;
} break;
case 4 : {
cmd->fps_out_den = 1;
cmd->fps_out_flex = 0;
} break;
case 5 : {
cmd->fps_out_flex = 0;
} break;
case 6 : {
} break;
default : {
mpp_err("invalid in/out frame rate,"
" use \"-r numerator:denominator:flex\""
" for set the input to the same fps as the output, such as 50:1:1\n"
" or \"-r numerator:denominator/flex-numerator:denominator:flex\""
" for set input and output separately, such as 40:1:1/30:1:0\n");
goto PARSE_OPINIONS_OUT;
} break;
}
} else {
mpp_err("invalid output frame rate\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'l' : {
if (next) {
cmd->loop_cnt = atoi(next);
} else {
mpp_err("invalid loop count\n");
goto PARSE_OPINIONS_OUT;
}
} break;
case 'x': {
if (next) {
size_t len = strnlen(next, MAX_FILE_NAME_LENGTH);
if (len) {
cmd->file_cfg = mpp_calloc(char, len + 1);
strncpy(cmd->file_cfg, next, len);
cmd->cfg_ini = iniparser_load(cmd->file_cfg);
}
} else {
mpp_err("input file is invalid\n");
goto PARSE_OPINIONS_OUT;
}
} break;
default : {
mpp_err("skip invalid opt %c\n", *opt);
} break;
}
optindex++;
}
}
ret = MPP_OK;
/* check essential parameter */
if (cmd->type <= MPP_VIDEO_CodingAutoDetect) {
mpp_err("invalid type %d\n", cmd->type);
ret = MPP_NOK;
}
if (!cmd->hor_stride)
cmd->hor_stride = mpi_enc_width_default_stride(cmd->width, cmd->format);
if (!cmd->ver_stride)
cmd->ver_stride = cmd->height;
if (cmd->width <= 0 || cmd->height <= 0 ||
cmd->hor_stride <= 0 || cmd->ver_stride <= 0) {
mpp_err("invalid w:h [%d:%d] stride [%d:%d]\n",
cmd->width, cmd->height, cmd->hor_stride, cmd->ver_stride);
ret = MPP_NOK;
}
PARSE_OPINIONS_OUT:
return ret;
}
MPP_RET mpi_enc_test_cmd_put(MpiEncTestArgs* cmd)
{
if (NULL == cmd)
return MPP_OK;
if (cmd->cfg_ini) {
iniparser_freedict(cmd->cfg_ini);
cmd->cfg_ini = NULL;
}
MPP_FREE(cmd->file_input);
MPP_FREE(cmd->file_output);
MPP_FREE(cmd->file_cfg);
MPP_FREE(cmd);
return MPP_OK;
}
MPP_RET mpi_enc_gen_ref_cfg(MppEncRefCfg ref, RK_S32 gop_mode)
{
MppEncRefLtFrmCfg lt_ref[4];
MppEncRefStFrmCfg st_ref[16];
RK_S32 lt_cnt = 0;
RK_S32 st_cnt = 0;
MPP_RET ret = MPP_OK;
memset(&lt_ref, 0, sizeof(lt_ref));
memset(&st_ref, 0, sizeof(st_ref));
switch (gop_mode) {
case 3 : {
// tsvc4
// /-> P1 /-> P3 /-> P5 /-> P7
// / / / /
// //--------> P2 //--------> P6
// // //
// ///---------------------> P4
// ///
// P0 ------------------------------------------------> P8
lt_cnt = 1;
/* set 8 frame lt-ref gap */
lt_ref[0].lt_idx = 0;
lt_ref[0].temporal_id = 0;
lt_ref[0].ref_mode = REF_TO_PREV_LT_REF;
lt_ref[0].lt_gap = 8;
lt_ref[0].lt_delay = 0;
st_cnt = 9;
/* set tsvc4 st-ref struct */
/* st 0 layer 0 - ref */
st_ref[0].is_non_ref = 0;
st_ref[0].temporal_id = 0;
st_ref[0].ref_mode = REF_TO_TEMPORAL_LAYER;
st_ref[0].ref_arg = 0;
st_ref[0].repeat = 0;
/* st 1 layer 3 - non-ref */
st_ref[1].is_non_ref = 1;
st_ref[1].temporal_id = 3;
st_ref[1].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[1].ref_arg = 0;
st_ref[1].repeat = 0;
/* st 2 layer 2 - ref */
st_ref[2].is_non_ref = 0;
st_ref[2].temporal_id = 2;
st_ref[2].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[2].ref_arg = 0;
st_ref[2].repeat = 0;
/* st 3 layer 3 - non-ref */
st_ref[3].is_non_ref = 1;
st_ref[3].temporal_id = 3;
st_ref[3].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[3].ref_arg = 0;
st_ref[3].repeat = 0;
/* st 4 layer 1 - ref */
st_ref[4].is_non_ref = 0;
st_ref[4].temporal_id = 1;
st_ref[4].ref_mode = REF_TO_PREV_LT_REF;
st_ref[4].ref_arg = 0;
st_ref[4].repeat = 0;
/* st 5 layer 3 - non-ref */
st_ref[5].is_non_ref = 1;
st_ref[5].temporal_id = 3;
st_ref[5].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[5].ref_arg = 0;
st_ref[5].repeat = 0;
/* st 6 layer 2 - ref */
st_ref[6].is_non_ref = 0;
st_ref[6].temporal_id = 2;
st_ref[6].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[6].ref_arg = 0;
st_ref[6].repeat = 0;
/* st 7 layer 3 - non-ref */
st_ref[7].is_non_ref = 1;
st_ref[7].temporal_id = 3;
st_ref[7].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[7].ref_arg = 0;
st_ref[7].repeat = 0;
/* st 8 layer 0 - ref */
st_ref[8].is_non_ref = 0;
st_ref[8].temporal_id = 0;
st_ref[8].ref_mode = REF_TO_TEMPORAL_LAYER;
st_ref[8].ref_arg = 0;
st_ref[8].repeat = 0;
} break;
case 2 : {
// tsvc3
// /-> P1 /-> P3
// / /
// //--------> P2
// //
// P0/---------------------> P4
lt_cnt = 0;
st_cnt = 5;
/* set tsvc4 st-ref struct */
/* st 0 layer 0 - ref */
st_ref[0].is_non_ref = 0;
st_ref[0].temporal_id = 0;
st_ref[0].ref_mode = REF_TO_TEMPORAL_LAYER;
st_ref[0].ref_arg = 0;
st_ref[0].repeat = 0;
/* st 1 layer 2 - non-ref */
st_ref[1].is_non_ref = 1;
st_ref[1].temporal_id = 2;
st_ref[1].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[1].ref_arg = 0;
st_ref[1].repeat = 0;
/* st 2 layer 1 - ref */
st_ref[2].is_non_ref = 0;
st_ref[2].temporal_id = 1;
st_ref[2].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[2].ref_arg = 0;
st_ref[2].repeat = 0;
/* st 3 layer 2 - non-ref */
st_ref[3].is_non_ref = 1;
st_ref[3].temporal_id = 2;
st_ref[3].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[3].ref_arg = 0;
st_ref[3].repeat = 0;
/* st 4 layer 0 - ref */
st_ref[4].is_non_ref = 0;
st_ref[4].temporal_id = 0;
st_ref[4].ref_mode = REF_TO_TEMPORAL_LAYER;
st_ref[4].ref_arg = 0;
st_ref[4].repeat = 0;
} break;
case 1 : {
// tsvc2
// /-> P1
// /
// P0--------> P2
lt_cnt = 0;
st_cnt = 3;
/* set tsvc4 st-ref struct */
/* st 0 layer 0 - ref */
st_ref[0].is_non_ref = 0;
st_ref[0].temporal_id = 0;
st_ref[0].ref_mode = REF_TO_TEMPORAL_LAYER;
st_ref[0].ref_arg = 0;
st_ref[0].repeat = 0;
/* st 1 layer 2 - non-ref */
st_ref[1].is_non_ref = 1;
st_ref[1].temporal_id = 1;
st_ref[1].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[1].ref_arg = 0;
st_ref[1].repeat = 0;
/* st 2 layer 1 - ref */
st_ref[2].is_non_ref = 0;
st_ref[2].temporal_id = 0;
st_ref[2].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[2].ref_arg = 0;
st_ref[2].repeat = 0;
} break;
default : {
mpp_err_f("unsupport gop mode %d\n", gop_mode);
} break;
}
if (lt_cnt || st_cnt) {
ret = mpp_enc_ref_cfg_set_cfg_cnt(ref, lt_cnt, st_cnt);
if (lt_cnt)
ret = mpp_enc_ref_cfg_add_lt_cfg(ref, lt_cnt, lt_ref);
if (st_cnt)
ret = mpp_enc_ref_cfg_add_st_cfg(ref, st_cnt, st_ref);
/* check and get dpb size */
ret = mpp_enc_ref_cfg_check(ref);
}
return ret;
}
MPP_RET mpi_enc_gen_smart_gop_ref_cfg(MppEncRefCfg ref, RK_S32 gop_len, RK_S32 vi_len)
{
MppEncRefLtFrmCfg lt_ref[4];
MppEncRefStFrmCfg st_ref[16];
RK_S32 lt_cnt = 1;
RK_S32 st_cnt = 8;
RK_S32 pos = 0;
MPP_RET ret = MPP_OK;
memset(&lt_ref, 0, sizeof(lt_ref));
memset(&st_ref, 0, sizeof(st_ref));
ret = mpp_enc_ref_cfg_set_cfg_cnt(ref, lt_cnt, st_cnt);
/* set 8 frame lt-ref gap */
lt_ref[0].lt_idx = 0;
lt_ref[0].temporal_id = 0;
lt_ref[0].ref_mode = REF_TO_PREV_LT_REF;
lt_ref[0].lt_gap = gop_len;
lt_ref[0].lt_delay = 0;
ret = mpp_enc_ref_cfg_add_lt_cfg(ref, 1, lt_ref);
/* st 0 layer 0 - ref */
st_ref[pos].is_non_ref = 0;
st_ref[pos].temporal_id = 0;
st_ref[pos].ref_mode = REF_TO_PREV_INTRA;
st_ref[pos].ref_arg = 0;
st_ref[pos].repeat = 0;
pos++;
/* st 1 layer 1 - non-ref */
if (vi_len > 1) {
st_ref[pos].is_non_ref = 0;
st_ref[pos].temporal_id = 1;
st_ref[pos].ref_mode = REF_TO_PREV_REF_FRM;
st_ref[pos].ref_arg = 0;
st_ref[pos].repeat = vi_len - 2;
pos++;
}
st_ref[pos].is_non_ref = 0;
st_ref[pos].temporal_id = 0;
st_ref[pos].ref_mode = REF_TO_PREV_INTRA;
st_ref[pos].ref_arg = 0;
st_ref[pos].repeat = 0;
pos++;
ret = mpp_enc_ref_cfg_add_st_cfg(ref, pos, st_ref);
/* check and get dpb size */
ret = mpp_enc_ref_cfg_check(ref);
return ret;
}
MPP_RET mpi_enc_gen_osd_data(MppEncOSDData *osd_data, MppBuffer osd_buf, RK_U32 frame_cnt)
{
RK_U32 k = 0;
RK_U32 buf_size = 0;
RK_U32 buf_offset = 0;
RK_U8 *buf = mpp_buffer_get_ptr(osd_buf);
osd_data->num_region = 8;
osd_data->buf = osd_buf;
for (k = 0; k < osd_data->num_region; k++) {
MppEncOSDRegion *region = &osd_data->region[k];
RK_U8 idx = k;
region->enable = 1;
region->inverse = frame_cnt & 1;
region->start_mb_x = k * 3;
region->start_mb_y = k * 2;
region->num_mb_x = 2;
region->num_mb_y = 2;
buf_size = region->num_mb_x * region->num_mb_y * 256;
buf_offset = k * buf_size;
osd_data->region[k].buf_offset = buf_offset;
memset(buf + buf_offset, idx, buf_size);
}
return MPP_OK;
}
MPP_RET mpi_enc_gen_osd_plt(MppEncOSDPlt *osd_plt, RK_U32 *table)
{
RK_U32 k = 0;
if (osd_plt->data && table) {
for (k = 0; k < 256; k++)
osd_plt->data[k].val = table[k % 8];
}
return MPP_OK;
}
static OptionInfo mpi_enc_cmd[] = {
{"i", "input_file", "input bitstream file"},
{"o", "output_file", "output bitstream file, "},
{"w", "width", "the width of input picture"},
{"h", "height", "the height of input picture"},
{"f", "format", "the format of input picture"},
{"t", "type", "output stream coding type"},
{"n", "max frame number", "max encoding frame number"},
{"g", "gop_mode", "gop reference mode"},
{"d", "debug", "debug flag"},
{"b", "bps target:min:max", "set tareget bps"},
{"r", "in/output fps", "set input and output frame rate"},
{"l", "loop count", "loop encoding times for each frame"},
};
MPP_RET mpi_enc_test_cmd_show_opt(MpiEncTestArgs* cmd)
{
mpp_log("cmd parse result:\n");
mpp_log("input file name: %s\n", cmd->file_input);
mpp_log("output file name: %s\n", cmd->file_output);
mpp_log("width : %d\n", cmd->width);
mpp_log("height : %d\n", cmd->height);
mpp_log("format : %d\n", cmd->format);
mpp_log("type : %d\n", cmd->type);
return MPP_OK;
}
void mpi_enc_test_help(void)
{
mpp_log("usage: mpi_enc_test [options]\n");
show_options(mpi_enc_cmd);
mpp_show_support_format();
mpp_show_color_format();
}