Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

H.264 updates #25

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
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