diff --git a/helpers/check-va-api.c b/helpers/check-va-api.c index b7ccc506e7ad0f5718fe8cbd53a5d5236923629c..b337f51f6f1a646d4f0f1367fd0ac8af7ec91496 100644 --- a/helpers/check-va-api.c +++ b/helpers/check-va-api.c @@ -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); }