Skip to content
Snippets Groups Projects
Commit 3876a193 authored by Ludovico de Nittis's avatar Ludovico de Nittis
Browse files

check-va-api: Decode H264 and fallback to MPEG2 and VAProfileNone


Some Intel GPUs don't have the profile "VAProfileNone".

For this reason we try "VAProfileH264Main" instead, that should be
supported since Intel GMA 4500 and Radeon HD 2000 and GeForce 8.
For additional coverage we also fallback to "VAProfileMPEG2Simple", that
has a similar GPU compatibility and lastly to "VAProfileNone".

Fixes: #24

Signed-off-by: default avatarLudovico de Nittis <ludovico.denittis@collabora.com>
parent 43d1cb7f
No related branches found
No related tags found
1 merge request!180check-va-api: Try to decode H264Main and fallback to MPEG2Simple
Pipeline #5384 passed
......@@ -52,6 +52,94 @@ struct option long_options[] =
{ NULL, 0, NULL, 0 }
};
/* Pseudo-randomly generated MPEG2 video clip with one I-frame */
static unsigned char clip_mpeg2[] =
{
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x28, 0x00, 0x2f, 0x64, 0x36, 0x00, 0x2d, 0xd0, 0x40, 0x00, 0x2d, 0x60,
0x12, 0x00, 0x2a, 0x61, 0x20, 0x00, 0x3e, 0x65,
};
#define CLIP_SIZE_MPEG2 sizeof(clip_mpeg2) / sizeof(clip_mpeg2[0])
static VAPictureParameterBufferMPEG2 pic_param_mpeg2 =
{
/* Limit the picture buffer to 16x16 */
.horizontal_size = 16,
.vertical_size = 16,
.picture_coding_type = 1, /* I-frame */
};
static VAIQMatrixBufferMPEG2 iq_matrix_mpeg2 =
{
/* Do not do anything particular here */
.load_intra_quantiser_matrix = 1,
.load_non_intra_quantiser_matrix = 1,
.load_chroma_intra_quantiser_matrix = 0,
.load_chroma_non_intra_quantiser_matrix = 0,
.intra_quantiser_matrix = {0},
.non_intra_quantiser_matrix = {0},
.chroma_intra_quantiser_matrix = {0},
.chroma_non_intra_quantiser_matrix = {0},
};
static VASliceParameterBufferMPEG2 slice_param_mpeg2 =
{
.slice_data_size = CLIP_SIZE_MPEG2,
.slice_data_offset = 0,
.slice_data_flag = 0,
/* Assume a slice with a 64bit header */
.macroblock_offset = 64,
};
/* Pseudo-randomly generated H264 video clip with one I-frame */
static unsigned int clip_h264[] =
{
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
0xca123456, 0xe2255446, 0x9a61c747, 0xe10133c7, 0x71ccf20f, 0xfd2e5af3,
};
#define CLIP_SIZE_H264 sizeof(clip_h264) / sizeof(clip_h264[0])
static VAPictureParameterBufferH264 pic_param_h264 =
{
/* The size has been arbitrarily chosen */
.picture_width_in_mbs_minus1 = 10,
.picture_height_in_mbs_minus1 = 10,
.num_ref_frames = 1,
};
static VAIQMatrixBufferH264 iq_matrix_h264 =
{
/* Do not do anything particular here */
.ScalingList4x4 = {{0}},
.ScalingList8x8 = {{0}},
};
static VASliceParameterBufferH264 slice_param_h264 =
{
.slice_data_size = CLIP_SIZE_H264,
.slice_data_offset = 0,
.slice_data_flag = 0,
};
static void usage (int code) __attribute__((__noreturn__));
/*
......@@ -92,6 +180,7 @@ main (int argc,
#define do_vaapi_or_exit(expr) if (! _do_vaapi (#expr, expr)) goto out;
bool verbose = false;
bool decode_available = false;
int opt;
int surfaces_count = 2;
int ret = 1;
......@@ -112,6 +201,10 @@ main (int argc,
VAContextID context = VA_INVALID_ID;
VABufferID misc_buf_id = VA_INVALID_ID;
VABufferID pipeline_param_buf_id = VA_INVALID_ID;
VABufferID pic_param_buf = VA_INVALID_ID;
VABufferID iq_matrix_buf = VA_INVALID_ID;
VABufferID slice_param_buf = VA_INVALID_ID;
VABufferID slice_data_buf = VA_INVALID_ID;
VAEncMiscParameterBuffer *misc_param_buffer;
VAEncMiscParameterBufferQualityLevel *buffer_quality_level;
VAProcPipelineParameterBuffer pipeline_param_buf;
......@@ -152,11 +245,11 @@ main (int argc,
attr.type = VASurfaceAttribPixelFormat;
attr.flags = VA_SURFACE_ATTRIB_SETTABLE;
attr.value.type = VAGenericValueTypeInteger;
/* Arbitrarily use the 8-bit RGBA, assuming to be widely supported.
/* Arbitrarily use the 8-bit YUV 4:2:0, assuming to be widely supported.
* In case the current system doesn't support it, vaCreateSurfaces will fail
* and this test will exit returning 1 */
attr.value.value.i = VA_FOURCC_RGBA;
image_format.fourcc = VA_FOURCC_RGBA;
attr.value.value.i = VA_FOURCC_I420;
image_format.fourcc = VA_FOURCC_I420;
image_format.byte_order = VA_LSB_FIRST;
image_format.bits_per_pixel = 32;
......@@ -225,7 +318,7 @@ main (int argc,
}
/* Test the creation of two surfaces and an image */
do_vaapi_or_exit (vaCreateSurfaces (va_display, VA_RT_FORMAT_RGB32, width, height,
do_vaapi_or_exit (vaCreateSurfaces (va_display, VA_RT_FORMAT_YUV420, width, height,
surfaces, surfaces_count, &attr, 1));
do_vaapi_or_exit (vaCreateImage (va_display, &image_format, width, height, &img));
......@@ -241,44 +334,131 @@ main (int argc,
do_vaapi_or_exit (vaSyncSurface (va_display, surfaces[1]));
/* Assume VAProfileNone to be available. If it isn't vaCreateConfig will not return
* "VA_STATUS_SUCCESS" and this test will exit returning 1 */
do_vaapi_or_exit (vaCreateConfig (va_display, VAProfileNone, VAEntrypointVideoProc,
NULL, 0, &config));
do_vaapi_or_exit (vaCreateContext (va_display, config, width, height, 0, surfaces,
surfaces_count, &context));
/* Try to render a picture, tuning its encode quality */
do_vaapi_or_exit (vaCreateBuffer (va_display, context, VAEncMiscParameterBufferType,
sizeof (VAEncMiscParameterBuffer) + sizeof (VAEncMiscParameterBufferQualityLevel),
1, NULL, &misc_buf_id));
do_vaapi_or_exit (vaMapBuffer (va_display, misc_buf_id, (void **)&misc_param_buffer));
misc_param_buffer->type = VAEncMiscParameterTypeQualityLevel;
buffer_quality_level = (VAEncMiscParameterBufferQualityLevel *)misc_param_buffer->data;
/* 1 is always the highest possible quality level, we don't need to check VAConfigAttribEncQualityRange */
buffer_quality_level->quality_level = 1;
do_vaapi_or_exit (vaUnmapBuffer (va_display, misc_buf_id));
do_vaapi_or_exit (vaBeginPicture (va_display, context, surfaces[1]));
do_vaapi_or_exit (vaRenderPicture (va_display, context, &misc_buf_id, 1));
do_vaapi_or_exit (vaSyncSurface (va_display, surfaces[1]));
/* We assume to have at least one of VAProfileH264Main, VAProfileMPEG2Simple
* or VAProfileNone */
if (_do_vaapi ("Testing ability to decode VAProfileH264Main",
vaCreateConfig (va_display, VAProfileH264Main,
VAEntrypointVLD, NULL, 0, &config)))
{
decode_available = true;
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VAPictureParameterBufferType,
sizeof (VAPictureParameterBufferH264),
1, &pic_param_h264,
&pic_param_buf));
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VAIQMatrixBufferType,
sizeof (VAIQMatrixBufferH264),
1, &iq_matrix_h264,
&iq_matrix_buf));
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VASliceParameterBufferType,
sizeof (VASliceParameterBufferH264),
1, &slice_param_h264,
&slice_param_buf));
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VASliceDataBufferType,
CLIP_SIZE_H264, 1,
clip_h264, &slice_data_buf));
}
else if (_do_vaapi ("Testing ability to decode VAProfileMPEG2Simple",
vaCreateConfig (va_display, VAProfileMPEG2Simple,
VAEntrypointVLD, NULL, 0, &config)))
{
decode_available = true;
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VAPictureParameterBufferType,
sizeof (VAPictureParameterBufferMPEG2),
1, &pic_param_mpeg2,
&pic_param_buf));
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VAIQMatrixBufferType,
sizeof (VAIQMatrixBufferMPEG2),
1, &iq_matrix_mpeg2,
&iq_matrix_buf));
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VASliceParameterBufferType,
sizeof (VASliceParameterBufferMPEG2),
1, &slice_param_mpeg2,
&slice_param_buf));
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VASliceDataBufferType,
CLIP_SIZE_MPEG2, 1,
clip_mpeg2, &slice_data_buf));
}
else if (_do_vaapi ("Testing ability to use VAProfileNone video pre/post processing",
vaCreateConfig (va_display, VAProfileNone,
VAEntrypointVideoProc, NULL, 0, &config)))
{
do_vaapi_or_exit (vaCreateContext (va_display, config, width, height, 0,
surfaces, surfaces_count, &context));
/* Try to render a picture, tuning its encode quality */
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VAEncMiscParameterBufferType,
sizeof (VAEncMiscParameterBuffer) +
sizeof (VAEncMiscParameterBufferQualityLevel),
1, NULL, &misc_buf_id));
do_vaapi_or_exit (vaMapBuffer (va_display, misc_buf_id, (void **)&misc_param_buffer));
misc_param_buffer->type = VAEncMiscParameterTypeQualityLevel;
buffer_quality_level = (VAEncMiscParameterBufferQualityLevel *)misc_param_buffer->data;
/* 1 is always the highest possible quality level, we don't need to check
* VAConfigAttribEncQualityRange */
buffer_quality_level->quality_level = 1;
do_vaapi_or_exit (vaUnmapBuffer (va_display, misc_buf_id));
do_vaapi_or_exit (vaBeginPicture (va_display, context, surfaces[1]));
do_vaapi_or_exit (vaRenderPicture (va_display, context, &misc_buf_id, 1));
do_vaapi_or_exit (vaSyncSurface (va_display, surfaces[1]));
/* Try to render a picture from the first surface to the second,
* applying a crop to it */
memset (&pipeline_param_buf, 0, sizeof (pipeline_param_buf));
pipeline_param_buf.surface = surfaces[0];
pipeline_param_buf.surface_region = &input_region;
pipeline_param_buf.output_region = &output_region;
/* Set a green background */
pipeline_param_buf.output_background_color = 0xff00ff00;
pipeline_param_buf.output_color_standard = VAProcColorStandardNone;
do_vaapi_or_exit (vaCreateBuffer (va_display, context,
VAProcPipelineParameterBufferType,
sizeof (pipeline_param_buf), 1,
&pipeline_param_buf, &pipeline_param_buf_id));
do_vaapi_or_exit (vaBeginPicture (va_display, context, surfaces[1]));
do_vaapi_or_exit (vaRenderPicture (va_display, context, &pipeline_param_buf_id, 1));
do_vaapi_or_exit (vaEndPicture (va_display, context));
do_vaapi_or_exit (vaSyncSurface (va_display, surfaces[1]));
}
else
{
goto out;
}
/* Try to render a picture from the first surface to the second, applying a crop to it */
memset (&pipeline_param_buf, 0, sizeof (pipeline_param_buf));
pipeline_param_buf.surface = surfaces[0];
pipeline_param_buf.surface_region = &input_region;
pipeline_param_buf.output_region = &output_region;
/* Set a green background */
pipeline_param_buf.output_background_color = 0xff00ff00;
pipeline_param_buf.output_color_standard = VAProcColorStandardNone;
do_vaapi_or_exit (vaCreateBuffer (va_display, context, VAProcPipelineParameterBufferType,
sizeof (pipeline_param_buf), 1, &pipeline_param_buf, &pipeline_param_buf_id));
do_vaapi_or_exit (vaBeginPicture (va_display, context, surfaces[1]));
do_vaapi_or_exit (vaRenderPicture (va_display, context, &pipeline_param_buf_id, 1));
do_vaapi_or_exit (vaEndPicture (va_display, context));
do_vaapi_or_exit (vaSyncSurface (va_display, surfaces[1]));
if (decode_available)
{
do_vaapi_or_exit (vaCreateContext (va_display, config, width, height,
VA_PROGRESSIVE, surfaces,
surfaces_count, &context));
do_vaapi_or_exit (vaBeginPicture (va_display, context, surfaces[1]));
/* Send the buffers to the server */
do_vaapi_or_exit (vaRenderPicture (va_display, context, &pic_param_buf, 1));
do_vaapi_or_exit (vaRenderPicture (va_display, context, &iq_matrix_buf, 1));
do_vaapi_or_exit (vaRenderPicture (va_display, context, &slice_param_buf, 1));
do_vaapi_or_exit (vaRenderPicture (va_display, context, &slice_data_buf, 1));
/* We are done with the sending, now the server will start to process all
* pending operations */
do_vaapi_or_exit (vaEndPicture (va_display, context));
/* Blocks until all pending operations ends */
do_vaapi_or_exit (vaSyncSurface (va_display, surfaces[1]));
}
ret = 0;
......@@ -297,6 +477,14 @@ out:
vaDestroyConfig(va_display, config);
if (surfaces)
vaDestroySurfaces (va_display, surfaces, surfaces_count);
if (pic_param_buf != VA_INVALID_ID)
vaDestroyBuffer (va_display, pic_param_buf);
if (iq_matrix_buf != VA_INVALID_ID)
vaDestroyBuffer (va_display, iq_matrix_buf);
if (slice_param_buf != VA_INVALID_ID)
vaDestroyBuffer (va_display, slice_param_buf);
if (slice_data_buf != VA_INVALID_ID)
vaDestroyBuffer (va_display, slice_data_buf);
vaTerminate (va_display);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment