5520b9467a
Add a menu control V4L2_CID_MPEG_VIDEO_VP8_PROFILE for VP8 profile and make V4L2_CID_MPEG_VIDEO_VPX_PROFILE an alias of it. This new control is used to select the desired profile for VP8 encoder and query for supported profiles by VP8 encoder/decoder. Though we have originally a control V4L2_CID_MPEG_VIDEO_VPX_PROFILE and its name contains 'VPX', it works only for VP8 because supported profiles usually differ between VP8 and VP9. In addition, this control cannot be used for querying since it is not a menu control but an integer control, which cannot return an arbitrary set of supported profiles. The new control V4L2_CID_MPEG_VIDEO_VP8_PROFILE is a menu control as with controls for other codec profiles. (e.g. H264) In addition, this patch also fixes the use of V4L2_CID_MPEG_VIDEO_VPX_PROFILE in drivers of Qualcomm's venus and Samsung's s5p-mfc. Signed-off-by: Keiichi Watanabe <keiichiw@chromium.org> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
330 lines
9.1 KiB
C
330 lines
9.1 KiB
C
/*
|
|
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
|
* Copyright (C) 2017 Linaro Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
#include <linux/types.h>
|
|
#include <media/v4l2-ctrls.h>
|
|
|
|
#include "core.h"
|
|
#include "venc.h"
|
|
|
|
#define BITRATE_MIN 32000
|
|
#define BITRATE_MAX 160000000
|
|
#define BITRATE_DEFAULT 1000000
|
|
#define BITRATE_DEFAULT_PEAK (BITRATE_DEFAULT * 2)
|
|
#define BITRATE_STEP 100
|
|
#define SLICE_BYTE_SIZE_MAX 1024
|
|
#define SLICE_BYTE_SIZE_MIN 1024
|
|
#define SLICE_MB_SIZE_MAX 300
|
|
#define INTRA_REFRESH_MBS_MAX 300
|
|
#define AT_SLICE_BOUNDARY \
|
|
V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
|
|
|
|
static int venc_calc_bpframes(u32 gop_size, u32 conseq_b, u32 *bf, u32 *pf)
|
|
{
|
|
u32 half = (gop_size - 1) >> 1;
|
|
u32 b, p, ratio;
|
|
bool found = false;
|
|
|
|
if (!gop_size)
|
|
return -EINVAL;
|
|
|
|
*bf = *pf = 0;
|
|
|
|
if (!conseq_b) {
|
|
*pf = gop_size - 1;
|
|
return 0;
|
|
}
|
|
|
|
b = p = half;
|
|
|
|
for (; b <= gop_size - 1; b++, p--) {
|
|
if (b % p)
|
|
continue;
|
|
|
|
ratio = b / p;
|
|
|
|
if (ratio == conseq_b) {
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
if (ratio > conseq_b)
|
|
break;
|
|
}
|
|
|
|
if (!found)
|
|
return -EINVAL;
|
|
|
|
if (b + p + 1 != gop_size)
|
|
return -EINVAL;
|
|
|
|
*bf = b;
|
|
*pf = p;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
{
|
|
struct venus_inst *inst = ctrl_to_inst(ctrl);
|
|
struct venc_controls *ctr = &inst->controls.enc;
|
|
u32 bframes;
|
|
int ret;
|
|
|
|
switch (ctrl->id) {
|
|
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
|
|
ctr->bitrate_mode = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_BITRATE:
|
|
ctr->bitrate = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
|
|
ctr->bitrate_peak = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
|
|
ctr->h264_entropy_mode = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
|
|
ctr->profile.mpeg4 = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
|
|
ctr->profile.h264 = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
|
|
ctr->profile.vpx = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
|
|
ctr->level.mpeg4 = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
|
|
ctr->level.h264 = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
|
|
ctr->h264_i_qp = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
|
|
ctr->h264_p_qp = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
|
|
ctr->h264_b_qp = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
|
|
ctr->h264_min_qp = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
|
|
ctr->h264_max_qp = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
|
|
ctr->multi_slice_mode = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
|
|
ctr->multi_slice_max_bytes = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
|
|
ctr->multi_slice_max_mb = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
|
|
ctr->h264_loop_filter_alpha = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
|
|
ctr->h264_loop_filter_beta = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
|
|
ctr->h264_loop_filter_mode = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
|
|
ctr->header_mode = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
|
|
ret = venc_calc_bpframes(ctrl->val, ctr->num_b_frames, &bframes,
|
|
&ctr->num_p_frames);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ctr->gop_size = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
|
|
ctr->h264_i_period = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP:
|
|
ctr->vp8_min_qp = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP:
|
|
ctr->vp8_max_qp = ctrl->val;
|
|
break;
|
|
case V4L2_CID_MPEG_VIDEO_B_FRAMES:
|
|
ret = venc_calc_bpframes(ctr->gop_size, ctrl->val, &bframes,
|
|
&ctr->num_p_frames);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ctr->num_b_frames = bframes;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct v4l2_ctrl_ops venc_ctrl_ops = {
|
|
.s_ctrl = venc_op_s_ctrl,
|
|
};
|
|
|
|
int venc_ctrl_init(struct venus_inst *inst)
|
|
{
|
|
int ret;
|
|
|
|
ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 27);
|
|
if (ret)
|
|
return ret;
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
|
|
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
|
|
~((1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
|
|
(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)),
|
|
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
|
|
V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
|
|
0, V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
|
|
V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY,
|
|
~((1 << V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE) |
|
|
(1 << V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE)),
|
|
V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
|
|
V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
|
|
0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
|
|
V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
|
|
~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
|
|
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
|
|
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
|
|
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) |
|
|
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) |
|
|
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH)),
|
|
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
|
|
V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
|
|
0, V4L2_MPEG_VIDEO_H264_LEVEL_1_0);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
|
|
AT_SLICE_BOUNDARY,
|
|
0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_HEADER_MODE,
|
|
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
|
|
1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
|
|
V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
|
|
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
|
|
0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
|
|
|
|
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
|
|
V4L2_MPEG_VIDEO_VP8_PROFILE_3,
|
|
0, V4L2_MPEG_VIDEO_VP8_PROFILE_0);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_BITRATE, BITRATE_MIN, BITRATE_MAX,
|
|
BITRATE_STEP, BITRATE_DEFAULT);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, BITRATE_MIN, BITRATE_MAX,
|
|
BITRATE_STEP, BITRATE_DEFAULT_PEAK);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 26);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 28);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, 1, 51, 1, 30);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 1, 51, 1, 1);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 1, 51, 1, 51);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, SLICE_BYTE_SIZE_MIN,
|
|
SLICE_BYTE_SIZE_MAX, 1, SLICE_BYTE_SIZE_MIN);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1,
|
|
SLICE_MB_SIZE_MAX, 1, 1);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
|
|
0, INTRA_REFRESH_MBS_MAX, 1, 0);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 12);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, 1, 128, 1, 1);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, 1, 128, 1, 128);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 4, 1, 0);
|
|
|
|
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
|
V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, 0, (1 << 16) - 1, 1, 0);
|
|
|
|
ret = inst->ctrl_handler.error;
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler);
|
|
if (ret)
|
|
goto err;
|
|
|
|
return 0;
|
|
err:
|
|
v4l2_ctrl_handler_free(&inst->ctrl_handler);
|
|
return ret;
|
|
}
|
|
|
|
void venc_ctrl_deinit(struct venus_inst *inst)
|
|
{
|
|
v4l2_ctrl_handler_free(&inst->ctrl_handler);
|
|
}
|