Skip to content
21 changes: 17 additions & 4 deletions include/h264-ctrls.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <linux/videodev2.h>

/* Our pixel format isn't stable at the moment */
#define V4L2_PIX_FMT_H264_SLICE_RAW v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */
#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */

/*
* This is put insanely high to avoid conflicting with controls that
Expand All @@ -26,6 +26,8 @@
#define V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (V4L2_CID_MPEG_BASE+1002)
#define V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (V4L2_CID_MPEG_BASE+1003)
#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_MPEG_BASE+1004)
#define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (V4L2_CID_MPEG_BASE+1005)
#define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_MPEG_BASE+1006)

/* enum v4l2_ctrl_type type values */
#define V4L2_CTRL_TYPE_H264_SPS 0x0110
Expand All @@ -34,6 +36,16 @@
#define V4L2_CTRL_TYPE_H264_SLICE_PARAMS 0x0113
#define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114

enum v4l2_mpeg_video_h264_decode_mode {
V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED,
V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
};

enum v4l2_mpeg_video_h264_start_code {
V4L2_MPEG_VIDEO_H264_START_CODE_NONE,
V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
};

#define V4L2_H264_SPS_CONSTRAINT_SET0_FLAG 0x01
#define V4L2_H264_SPS_CONSTRAINT_SET1_FLAG 0x02
#define V4L2_H264_SPS_CONSTRAINT_SET2_FLAG 0x04
Expand Down Expand Up @@ -125,6 +137,10 @@ struct v4l2_h264_pred_weight_table {
struct v4l2_ctrl_h264_slice_params {
/* Size in bytes, including header */
__u32 size;

/* Offset in bytes to the start of slice in the OUTPUT buffer. */
__u32 start_byte_offset;

/* Offset in bits to slice_data() from the beginning of this slice. */
__u32 header_bit_size;

Expand Down Expand Up @@ -186,9 +202,6 @@ struct v4l2_ctrl_h264_decode_params {
struct v4l2_h264_dpb_entry dpb[16];
__u16 num_slices;
__u16 nal_ref_idc;
__u8 ref_pic_list_p0[32];
__u8 ref_pic_list_b0[32];
__u8 ref_pic_list_b1[32];
__s32 top_field_order_cnt;
__s32 bottom_field_order_cnt;
__u32 flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */
Expand Down
2 changes: 1 addition & 1 deletion src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ VAStatus RequestQueryConfigProfiles(VADriverContextP context,

found = v4l2_find_format(driver_data->video_fd,
V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_PIX_FMT_H264_SLICE_RAW);
V4L2_PIX_FMT_H264_SLICE);
if (found && index < (V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES - 5)) {
profiles[index++] = VAProfileH264Main;
profiles[index++] = VAProfileH264High;
Expand Down
4 changes: 3 additions & 1 deletion src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
case VAProfileH264ConstrainedBaseline:
case VAProfileH264MultiviewHigh:
case VAProfileH264StereoHigh:
pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW;
pixelformat = V4L2_PIX_FMT_H264_SLICE;
/* Query decode mode and start code */
h264_get_controls(driver_data, context_object);
break;

case VAProfileHEVCMain:
Expand Down
1 change: 1 addition & 0 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct object_context {

/* H264 only */
struct h264_dpb dpb;
bool h264_start_code;
};

VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
Expand Down
129 changes: 105 additions & 24 deletions src/h264.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ static void h264_fill_dpb(struct request_data *data,
}

dpb->frame_num = entry->pic.frame_idx;
dpb->pic_num = entry->pic.picture_id;
dpb->top_field_order_cnt = entry->pic.TopFieldOrderCnt;
dpb->bottom_field_order_cnt = entry->pic.BottomFieldOrderCnt;

Expand All @@ -218,9 +219,23 @@ static void h264_va_picture_to_v4l2(struct request_data *driver_data,
struct v4l2_ctrl_h264_pps *pps,
struct v4l2_ctrl_h264_sps *sps)
{
unsigned char *b;
unsigned char nal_ref_idc;
unsigned char nal_unit_type;

/* Extract missing nal_ref_idc and nal_unit_type */
b = surface->source_data;
if (context->h264_start_code)
b += 3;
nal_ref_idc = (b[0] >> 5) & 0x3;
nal_unit_type = b[0] & 0x1f;

h264_fill_dpb(driver_data, context, decode);

decode->num_slices = surface->slices_count;
decode->nal_ref_idc = nal_ref_idc;
if (nal_unit_type == 5)
decode->flags = V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC;
decode->top_field_order_cnt = VAPicture->CurrPic.TopFieldOrderCnt;
decode->bottom_field_order_cnt = VAPicture->CurrPic.BottomFieldOrderCnt;

Expand Down Expand Up @@ -255,6 +270,7 @@ static void h264_va_picture_to_v4l2(struct request_data *driver_data,
if (VAPicture->pic_fields.bits.redundant_pic_cnt_present_flag)
pps->flags |= V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT;

sps->max_num_ref_frames = VAPicture->num_ref_frames;
sps->chroma_format_idc = VAPicture->seq_fields.bits.chroma_format_idc;
sps->bit_depth_luma_minus8 = VAPicture->bit_depth_luma_minus8;
sps->bit_depth_chroma_minus8 = VAPicture->bit_depth_chroma_minus8;
Expand Down Expand Up @@ -330,9 +346,12 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data,
struct v4l2_ctrl_h264_slice_params *slice)
{
slice->size = VASlice->slice_data_size;
if (context->h264_start_code)
slice->size += 3;
slice->header_bit_size = VASlice->slice_data_bit_offset;
slice->first_mb_in_slice = VASlice->first_mb_in_slice;
slice->slice_type = VASlice->slice_type;
slice->frame_num = VAPicture->frame_num;
slice->cabac_init_idc = VASlice->cabac_init_idc;
slice->slice_qp_delta = VASlice->slice_qp_delta;
slice->disable_deblocking_filter_idc =
Expand Down Expand Up @@ -405,8 +424,67 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data,
VASlice->chroma_offset_l1);
}

int h264_get_controls(struct request_data *driver_data,
struct object_context *context)
{
struct v4l2_ext_control controls[2] = {
{
.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE,
}, {
.id = V4L2_CID_MPEG_VIDEO_H264_START_CODE,
}
};
int rc;

rc = v4l2_get_controls(driver_data->video_fd, -1, controls, 2);
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;

switch (controls[0].value) {
case V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED:
break;
case V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED:
break;
default:
request_log("Unsupported decode mode\n");
return VA_STATUS_ERROR_OPERATION_FAILED;
}

switch (controls[1].value) {
case V4L2_MPEG_VIDEO_H264_START_CODE_NONE:
break;
case V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B:
context->h264_start_code = true;
break;
default:
request_log("Unsupported start code\n");
return VA_STATUS_ERROR_OPERATION_FAILED;
}

return VA_STATUS_SUCCESS;
}

static inline __u8 h264_profile_to_idc(VAProfile profile)
{
switch (profile) {
case VAProfileH264Main:
return 77;
case VAProfileH264High:
return 100;
case VAProfileH264ConstrainedBaseline:
return 66;
case VAProfileH264MultiviewHigh:
return 118;
case VAProfileH264StereoHigh:
return 128;
default:
return 0;
}
}

int h264_set_controls(struct request_data *driver_data,
struct object_context *context,
VAProfile profile,
struct object_surface *surface)
{
struct v4l2_ctrl_h264_scaling_matrix matrix = { 0 };
Expand Down Expand Up @@ -435,31 +513,34 @@ int h264_set_controls(struct request_data *driver_data,
&surface->params.h264.slice,
&surface->params.h264.picture, &slice);

rc = v4l2_set_control(driver_data->video_fd, surface->request_fd,
V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, &decode,
sizeof(decode));
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;

rc = v4l2_set_control(driver_data->video_fd, surface->request_fd,
V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, &slice,
sizeof(slice));
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;

rc = v4l2_set_control(driver_data->video_fd, surface->request_fd,
V4L2_CID_MPEG_VIDEO_H264_PPS, &pps, sizeof(pps));
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;

rc = v4l2_set_control(driver_data->video_fd, surface->request_fd,
V4L2_CID_MPEG_VIDEO_H264_SPS, &sps, sizeof(sps));
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;
sps.profile_idc = h264_profile_to_idc(profile);

struct v4l2_ext_control controls[5] = {
{
.id = V4L2_CID_MPEG_VIDEO_H264_SPS,
.ptr = &sps,
.size = sizeof(sps),
}, {
.id = V4L2_CID_MPEG_VIDEO_H264_PPS,
.ptr = &pps,
.size = sizeof(pps),
}, {
.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
.ptr = &matrix,
.size = sizeof(matrix),
}, {
.id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
.ptr = &slice,
.size = sizeof(slice),
}, {
.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
.ptr = &decode,
.size = sizeof(decode),
}
};

rc = v4l2_set_control(driver_data->video_fd, surface->request_fd,
V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, &matrix,
sizeof(matrix));
rc = v4l2_set_controls(driver_data->video_fd, surface->request_fd,
controls, 5);
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;

Expand Down
3 changes: 3 additions & 0 deletions src/h264.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ struct h264_dpb {
unsigned int age;
};

int h264_get_controls(struct request_data *driver_data,
struct object_context *context);
int h264_set_controls(struct request_data *data,
struct object_context *context,
VAProfile profile,
struct object_surface *surface);

#endif
15 changes: 13 additions & 2 deletions src/picture.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "autoconfig.h"

static VAStatus codec_store_buffer(struct request_data *driver_data,
struct object_context *context,
VAProfile profile,
struct object_surface *surface_object,
struct object_buffer *buffer_object)
Expand All @@ -63,6 +64,14 @@ static VAStatus codec_store_buffer(struct request_data *driver_data,
* RenderPicture), we can't use a V4L2 buffer directly
* and have to copy from a regular buffer.
*/
if (context->h264_start_code) {
static const char start_code[3] = { 0x00, 0x00, 0x01 };

memcpy(surface_object->source_data +
surface_object->slices_size,
start_code, sizeof(start_code));
surface_object->slices_size += sizeof(start_code);
}
memcpy(surface_object->source_data +
surface_object->slices_size,
buffer_object->data,
Expand Down Expand Up @@ -184,7 +193,8 @@ static VAStatus codec_set_controls(struct request_data *driver_data,
case VAProfileH264ConstrainedBaseline:
case VAProfileH264MultiviewHigh:
case VAProfileH264StereoHigh:
rc = h264_set_controls(driver_data, context, surface_object);
rc = h264_set_controls(driver_data, context, profile,
surface_object);
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;
break;
Expand Down Expand Up @@ -255,7 +265,8 @@ VAStatus RequestRenderPicture(VADriverContextP context, VAContextID context_id,
if (buffer_object == NULL)
return VA_STATUS_ERROR_INVALID_BUFFER;

rc = codec_store_buffer(driver_data, config_object->profile,
rc = codec_store_buffer(driver_data, context_object,
config_object->profile,
surface_object, buffer_object);
if (rc != VA_STATUS_SUCCESS)
return rc;
Expand Down
Loading