media: allegro: make frame rate configurable

The allegro dvt codec adjust the encoding speed according to a
configured frame rate. Furthermore, the frame rate is written into the
coded stream.

Ensure that the coded video data has the correct frame rate by
implementing s_parm for setting the frame rate from user space.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Michael Tretter 2020-03-16 16:26:31 +01:00 committed by Mauro Carvalho Chehab
parent e74145c233
commit 6179184020
1 changed files with 58 additions and 5 deletions

View File

@ -7,6 +7,7 @@
#include <linux/bits.h>
#include <linux/firmware.h>
#include <linux/gcd.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@ -41,6 +42,8 @@
#define ALLEGRO_HEIGHT_DEFAULT 1080
#define ALLEGRO_HEIGHT_MAX 2160
#define ALLEGRO_FRAMERATE_DEFAULT ((struct v4l2_fract) { 30, 1 })
#define ALLEGRO_GOP_SIZE_DEFAULT 25
#define ALLEGRO_GOP_SIZE_MAX 1000
@ -177,6 +180,7 @@ struct allegro_channel {
unsigned int width;
unsigned int height;
unsigned int stride;
struct v4l2_fract framerate;
enum v4l2_colorspace colorspace;
enum v4l2_ycbcr_encoding ycbcr_enc;
@ -1138,8 +1142,9 @@ static int allegro_mcu_send_create_channel(struct allegro_dev *dev,
channel->bitrate_peak);
/* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */
msg.initial_rem_delay = msg.cpb_size;
msg.framerate = 25;
msg.clk_ratio = 1000;
msg.framerate = DIV_ROUND_UP(channel->framerate.numerator,
channel->framerate.denominator);
msg.clk_ratio = channel->framerate.denominator == 1001 ? 1001 : 1000;
msg.target_bitrate = channel->bitrate;
msg.max_bitrate = channel->bitrate_peak;
msg.initial_qp = 25;
@ -1448,9 +1453,11 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel,
sps->vui.chroma_loc_info_present_flag = 1;
sps->vui.chroma_sample_loc_type_top_field = 0;
sps->vui.chroma_sample_loc_type_bottom_field = 0;
sps->vui.timing_info_present_flag = 1;
sps->vui.num_units_in_tick = 1;
sps->vui.time_scale = 50;
sps->vui.num_units_in_tick = channel->framerate.denominator;
sps->vui.time_scale = 2 * channel->framerate.numerator;
sps->vui.fixed_frame_rate_flag = 1;
sps->vui.nal_hrd_parameters_present_flag = 0;
sps->vui.vcl_hrd_parameters_present_flag = 1;
@ -2117,7 +2124,9 @@ static int allegro_create_channel(struct allegro_channel *channel)
v4l2_dbg(1, debug, &dev->v4l2_dev,
"user %d: creating channel (%4.4s, %dx%d@%d)\n",
channel->user_id,
(char *)&channel->codec, channel->width, channel->height, 25);
(char *)&channel->codec, channel->width, channel->height,
DIV_ROUND_UP(channel->framerate.numerator,
channel->framerate.denominator));
min_level = select_minimum_h264_level(channel->width, channel->height);
if (channel->level < min_level) {
@ -2163,6 +2172,7 @@ static void allegro_set_default_params(struct allegro_channel *channel)
channel->width = ALLEGRO_WIDTH_DEFAULT;
channel->height = ALLEGRO_HEIGHT_DEFAULT;
channel->stride = round_up(channel->width, 32);
channel->framerate = ALLEGRO_FRAMERATE_DEFAULT;
channel->colorspace = V4L2_COLORSPACE_REC709;
channel->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
@ -2770,6 +2780,46 @@ static int allegro_ioctl_streamon(struct file *file, void *priv,
return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
}
static int allegro_g_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
struct allegro_channel *channel = fh_to_channel(fh);
struct v4l2_fract *timeperframe;
if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
timeperframe = &a->parm.output.timeperframe;
timeperframe->numerator = channel->framerate.denominator;
timeperframe->denominator = channel->framerate.numerator;
return 0;
}
static int allegro_s_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
struct allegro_channel *channel = fh_to_channel(fh);
struct v4l2_fract *timeperframe;
int div;
if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
timeperframe = &a->parm.output.timeperframe;
if (timeperframe->numerator == 0 || timeperframe->denominator == 0)
return allegro_g_parm(file, fh, a);
div = gcd(timeperframe->denominator, timeperframe->numerator);
channel->framerate.numerator = timeperframe->denominator / div;
channel->framerate.denominator = timeperframe->numerator / div;
return 0;
}
static int allegro_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
@ -2808,6 +2858,9 @@ static const struct v4l2_ioctl_ops allegro_ioctl_ops = {
.vidioc_encoder_cmd = allegro_encoder_cmd,
.vidioc_enum_framesizes = allegro_enum_framesizes,
.vidioc_g_parm = allegro_g_parm,
.vidioc_s_parm = allegro_s_parm,
.vidioc_subscribe_event = allegro_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};