mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 08:11:16 +00:00
846 lines
27 KiB
C
846 lines
27 KiB
C
/* GStreamer
|
|
*
|
|
* Copyright (C) 2023 Igalia, S.L.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <gst/gst.h>
|
|
#include <gst/check/gstcheck.h>
|
|
#include <gst/vulkan/vulkan.h>
|
|
|
|
static GstVulkanInstance *instance;
|
|
static GstVulkanDevice *device;
|
|
static GstVulkanQueue *video_queue = NULL;
|
|
static GstVulkanQueue *graphics_queue = NULL;
|
|
|
|
static void
|
|
setup (void)
|
|
{
|
|
instance = gst_vulkan_instance_new ();
|
|
fail_unless (gst_vulkan_instance_open (instance, NULL));
|
|
}
|
|
|
|
static void
|
|
teardown (void)
|
|
{
|
|
gst_clear_object (&video_queue);
|
|
gst_clear_object (&graphics_queue);
|
|
gst_clear_object (&device);
|
|
gst_object_unref (instance);
|
|
}
|
|
|
|
struct QueueProps
|
|
{
|
|
guint expected_flags;
|
|
guint codec;
|
|
};
|
|
|
|
static gboolean
|
|
_choose_queue (GstVulkanDevice * device, GstVulkanQueue * _queue, gpointer data)
|
|
{
|
|
guint flags =
|
|
device->physical_device->queue_family_props[_queue->family].queueFlags;
|
|
guint32 codec =
|
|
device->physical_device->queue_family_ops[_queue->family].video;
|
|
struct QueueProps *qprops = data;
|
|
|
|
if ((flags & VK_QUEUE_TRANSFER_BIT) == VK_QUEUE_TRANSFER_BIT) {
|
|
gst_object_replace ((GstObject **) & graphics_queue,
|
|
GST_OBJECT_CAST (_queue));
|
|
}
|
|
|
|
if (((flags & qprops->expected_flags) == qprops->expected_flags)
|
|
&& ((codec & qprops->codec) == qprops->codec))
|
|
gst_object_replace ((GstObject **) & video_queue, GST_OBJECT_CAST (_queue));
|
|
|
|
|
|
return !(graphics_queue && video_queue);
|
|
}
|
|
|
|
static void
|
|
setup_queue (guint expected_flags, guint codec)
|
|
{
|
|
int i;
|
|
struct QueueProps qprops = { expected_flags, codec };
|
|
|
|
for (i = 0; i < instance->n_physical_devices; i++) {
|
|
device = gst_vulkan_device_new_with_index (instance, i);
|
|
fail_unless (gst_vulkan_device_open (device, NULL));
|
|
gst_vulkan_device_foreach_queue (device, _choose_queue, &qprops);
|
|
if (video_queue && GST_IS_VULKAN_QUEUE (video_queue)
|
|
&& graphics_queue && GST_IS_VULKAN_QUEUE (graphics_queue))
|
|
break;
|
|
gst_clear_object (&device);
|
|
gst_clear_object (&video_queue);
|
|
gst_clear_object (&graphics_queue);
|
|
}
|
|
}
|
|
|
|
static void
|
|
get_output_buffer (GstVulkanDecoder * dec, VkFormat vk_format,
|
|
GstVulkanDecoderPicture * pic)
|
|
{
|
|
GstBuffer *outbuf;
|
|
VkImageUsageFlags usage =
|
|
VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR
|
|
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
GstVideoFormat format = gst_vulkan_format_to_video_format (vk_format);
|
|
GstCaps *profile_caps, *caps = gst_caps_new_simple ("video/x-raw", "format",
|
|
G_TYPE_STRING, gst_video_format_to_string (format), "width", G_TYPE_INT,
|
|
320, "height", G_TYPE_INT, 240, NULL);
|
|
GstBufferPool *pool;
|
|
GstStructure *config;
|
|
|
|
gst_caps_set_features_simple (caps,
|
|
gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE, NULL));
|
|
|
|
profile_caps = gst_vulkan_decoder_profile_caps (dec);
|
|
fail_unless (profile_caps);
|
|
fail_unless (gst_vulkan_decoder_create_dpb_pool (dec, caps));
|
|
|
|
if (!dec->dedicated_dpb)
|
|
usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
|
|
|
|
pool = gst_vulkan_image_buffer_pool_new (device);
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
|
|
gst_buffer_pool_config_set_params (config, caps, 1024, 1, 0);
|
|
|
|
gst_caps_unref (caps);
|
|
|
|
gst_vulkan_image_buffer_pool_config_set_allocation_params (config, usage,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR, VK_ACCESS_TRANSFER_WRITE_BIT);
|
|
gst_vulkan_image_buffer_pool_config_set_decode_caps (config, profile_caps);
|
|
|
|
gst_caps_unref (profile_caps);
|
|
|
|
fail_unless (gst_buffer_pool_set_config (pool, config));
|
|
fail_unless (gst_buffer_pool_set_active (pool, TRUE));
|
|
|
|
fail_unless (gst_buffer_pool_acquire_buffer (pool, &outbuf, NULL) ==
|
|
GST_FLOW_OK);
|
|
|
|
fail_unless (gst_vulkan_decoder_picture_init (dec, pic, outbuf));
|
|
|
|
gst_buffer_unref (outbuf);
|
|
fail_unless (gst_buffer_pool_set_active (pool, FALSE));
|
|
gst_object_unref (pool);
|
|
}
|
|
|
|
static void
|
|
download_and_check_output_buffer (GstVulkanDecoder * dec, VkFormat vk_format,
|
|
GstVulkanDecoderPicture * pic)
|
|
{
|
|
GstVulkanOperation *exec;
|
|
GstVulkanCommandPool *cmd_pool;
|
|
GstBufferPool *out_pool = gst_vulkan_buffer_pool_new (dec->queue->device);
|
|
GstStructure *config = gst_buffer_pool_get_config (out_pool);
|
|
GstVideoFormat format = gst_vulkan_format_to_video_format (vk_format);
|
|
GstCaps *caps = gst_caps_new_simple ("video/x-raw", "format",
|
|
G_TYPE_STRING, gst_video_format_to_string (format), "width", G_TYPE_INT,
|
|
320, "height", G_TYPE_INT, 240, NULL);
|
|
GstBuffer *rawbuf;
|
|
GError *error = NULL;
|
|
GArray *barriers;
|
|
GstVideoInfo info;
|
|
GstMapInfo mapinfo;
|
|
guint i, n_mems, n_planes;
|
|
|
|
gst_buffer_pool_config_set_params (config, caps, 1, 0, 0);
|
|
gst_buffer_pool_set_config (out_pool, config);
|
|
|
|
gst_video_info_from_caps (&info, caps);
|
|
gst_caps_unref (caps);
|
|
|
|
gst_buffer_pool_set_active (out_pool, TRUE);
|
|
fail_unless (gst_buffer_pool_acquire_buffer (out_pool, &rawbuf, NULL)
|
|
== GST_FLOW_OK);
|
|
|
|
cmd_pool = gst_vulkan_queue_create_command_pool (graphics_queue, &error);
|
|
fail_unless (cmd_pool);
|
|
exec = gst_vulkan_operation_new (cmd_pool);
|
|
gst_object_unref (cmd_pool);
|
|
|
|
fail_unless (gst_vulkan_operation_begin (exec, &error));
|
|
gst_vulkan_operation_add_dependency_frame (exec, pic->out,
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
|
|
|
gst_vulkan_operation_add_frame_barrier (exec, pic->out,
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, NULL);
|
|
|
|
barriers = gst_vulkan_operation_retrieve_image_barriers (exec);
|
|
/* *INDENT-OFF* */
|
|
vkCmdPipelineBarrier2 (exec->cmd_buf->cmd, &(VkDependencyInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
|
.pImageMemoryBarriers = (gpointer) barriers->data,
|
|
.imageMemoryBarrierCount = barriers->len,
|
|
});
|
|
/* *INDENT-ON* */
|
|
|
|
n_planes = GST_VIDEO_INFO_N_PLANES (&info);
|
|
n_mems = gst_buffer_n_memory (pic->out);
|
|
|
|
for (i = 0; i < n_planes; i++) {
|
|
VkBufferImageCopy region;
|
|
GstMemory *out_mem;
|
|
GstVulkanBufferMemory *buf_mem;
|
|
GstVulkanImageMemory *img_mem;
|
|
gint idx;
|
|
const VkImageAspectFlags aspects[] = { VK_IMAGE_ASPECT_PLANE_0_BIT,
|
|
VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT,
|
|
};
|
|
VkImageAspectFlags plane_aspect;
|
|
|
|
idx = MIN (i, n_mems - 1);
|
|
img_mem = (GstVulkanImageMemory *) gst_buffer_peek_memory (pic->out, idx);
|
|
|
|
out_mem = gst_buffer_peek_memory (rawbuf, i);
|
|
buf_mem = (GstVulkanBufferMemory *) out_mem;
|
|
|
|
if (n_planes == n_mems)
|
|
plane_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
else
|
|
plane_aspect = aspects[i];
|
|
|
|
/* *INDENT-OFF* */
|
|
region = (VkBufferImageCopy) {
|
|
.bufferOffset = 0,
|
|
.bufferRowLength = GST_VIDEO_INFO_COMP_WIDTH (&info, i),
|
|
.bufferImageHeight = GST_VIDEO_INFO_COMP_HEIGHT (&info, i),
|
|
.imageSubresource = {
|
|
/* XXX: each plane is a buffer */
|
|
.aspectMask = plane_aspect,
|
|
.mipLevel = 0,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
.imageOffset = { .x = 0, .y = 0, .z = 0, },
|
|
.imageExtent = {
|
|
.width = GST_VIDEO_INFO_COMP_WIDTH (&info, i),
|
|
.height = GST_VIDEO_INFO_COMP_HEIGHT (&info, i),
|
|
.depth = 1,
|
|
}
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
vkCmdCopyImageToBuffer (exec->cmd_buf->cmd, img_mem->image,
|
|
g_array_index (barriers, VkImageMemoryBarrier2, 0).newLayout,
|
|
buf_mem->buffer, 1, ®ion);
|
|
}
|
|
|
|
g_array_unref (barriers);
|
|
|
|
fail_unless (gst_vulkan_operation_end (exec, &error));
|
|
|
|
gst_vulkan_operation_wait (exec);
|
|
gst_object_unref (exec);
|
|
|
|
fail_unless (gst_buffer_map (rawbuf, &mapinfo, GST_MAP_READ));
|
|
|
|
/* Check for a blue square */
|
|
/* Y */
|
|
for (i = 0; i < 0x12c00; i++)
|
|
fail_unless (mapinfo.data[i] == 0x29);
|
|
/* UV */
|
|
for (i = 0x12c00; i < 0x1c1f0; i++)
|
|
fail_unless (mapinfo.data[i] == 0xf0 && mapinfo.data[++i] == 0x6e);
|
|
gst_buffer_unmap (rawbuf, &mapinfo);
|
|
|
|
gst_buffer_unref (rawbuf);
|
|
fail_unless (gst_buffer_pool_set_active (out_pool, FALSE));
|
|
gst_object_unref (out_pool);
|
|
}
|
|
|
|
|
|
/* DECODER: 1 frame 320x240 blue box */
|
|
StdVideoH264HrdParameters h264_std_hrd = {
|
|
.cpb_cnt_minus1 = 0,
|
|
.bit_rate_scale = 4,
|
|
.cpb_size_scale = 0,
|
|
.reserved1 = 0,
|
|
.bit_rate_value_minus1 = {2928,},
|
|
.cpb_size_value_minus1 = {74999,},
|
|
.cbr_flag = {0,},
|
|
.initial_cpb_removal_delay_length_minus1 = 23,
|
|
.cpb_removal_delay_length_minus1 = 23,
|
|
.dpb_output_delay_length_minus1 = 23,
|
|
.time_offset_length = 24,
|
|
};
|
|
|
|
StdVideoH264SequenceParameterSetVui h264_std_vui = {
|
|
.flags = {
|
|
.aspect_ratio_info_present_flag = 1,
|
|
.overscan_info_present_flag = 0,
|
|
.overscan_appropriate_flag = 0,
|
|
.video_signal_type_present_flag = 0,
|
|
.video_full_range_flag = 1,
|
|
.color_description_present_flag = 0,
|
|
.chroma_loc_info_present_flag = 1,
|
|
.timing_info_present_flag = 1,
|
|
.fixed_frame_rate_flag = 1,
|
|
.bitstream_restriction_flag = 1,
|
|
.nal_hrd_parameters_present_flag = 1,
|
|
.vcl_hrd_parameters_present_flag = 0,
|
|
},
|
|
.aspect_ratio_idc = STD_VIDEO_H264_ASPECT_RATIO_IDC_SQUARE,
|
|
.sar_width = 1,
|
|
.sar_height = 1,
|
|
.video_format = 0,
|
|
.colour_primaries = 0,
|
|
.transfer_characteristics = 0,
|
|
.matrix_coefficients = 2,
|
|
.num_units_in_tick = 1,
|
|
.time_scale = 60,
|
|
.max_num_reorder_frames = 0,
|
|
.max_dec_frame_buffering = 2,
|
|
.chroma_sample_loc_type_top_field = 0,
|
|
.chroma_sample_loc_type_bottom_field = 0,
|
|
.pHrdParameters = &h264_std_hrd,
|
|
};
|
|
|
|
StdVideoH264SequenceParameterSet h264_std_sps = {
|
|
.flags = {
|
|
.constraint_set0_flag = 0,
|
|
.constraint_set1_flag = 0,
|
|
.constraint_set2_flag = 0,
|
|
.constraint_set3_flag = 0,
|
|
.constraint_set4_flag = 0,
|
|
.constraint_set5_flag = 0,
|
|
.direct_8x8_inference_flag = 1,
|
|
.mb_adaptive_frame_field_flag = 0,
|
|
.frame_mbs_only_flag = 1,
|
|
.delta_pic_order_always_zero_flag = 0,
|
|
.separate_colour_plane_flag = 0,
|
|
.gaps_in_frame_num_value_allowed_flag = 0,
|
|
.qpprime_y_zero_transform_bypass_flag = 0,
|
|
.frame_cropping_flag = 0,
|
|
.seq_scaling_matrix_present_flag = 0,
|
|
.vui_parameters_present_flag = 1,
|
|
},
|
|
.profile_idc = STD_VIDEO_H264_PROFILE_IDC_MAIN,
|
|
.level_idc = STD_VIDEO_H264_LEVEL_IDC_2_1,
|
|
.chroma_format_idc = STD_VIDEO_H264_CHROMA_FORMAT_IDC_420,
|
|
.seq_parameter_set_id = 0,
|
|
.bit_depth_luma_minus8 = 0,
|
|
.bit_depth_chroma_minus8 = 0,
|
|
.log2_max_frame_num_minus4 = 4,
|
|
.pic_order_cnt_type = STD_VIDEO_H264_POC_TYPE_2,
|
|
.offset_for_non_ref_pic = 0,
|
|
.offset_for_top_to_bottom_field = 0,
|
|
.log2_max_pic_order_cnt_lsb_minus4 = 0,
|
|
.num_ref_frames_in_pic_order_cnt_cycle = 0,
|
|
.max_num_ref_frames = 2,
|
|
.pic_width_in_mbs_minus1 = 19,
|
|
.pic_height_in_map_units_minus1 = 14,
|
|
.frame_crop_left_offset = 0,
|
|
.frame_crop_right_offset = 0,
|
|
.frame_crop_top_offset = 0,
|
|
.frame_crop_bottom_offset = 0,
|
|
.pOffsetForRefFrame = NULL,
|
|
.pScalingLists = NULL,
|
|
.pSequenceParameterSetVui = &h264_std_vui,
|
|
};
|
|
|
|
StdVideoH264PictureParameterSet h264_std_pps = {
|
|
.flags = {
|
|
.transform_8x8_mode_flag = 0,
|
|
.redundant_pic_cnt_present_flag = 0,
|
|
.constrained_intra_pred_flag = 0,
|
|
.deblocking_filter_control_present_flag = 1,
|
|
.weighted_pred_flag = 0,
|
|
.bottom_field_pic_order_in_frame_present_flag = 0,
|
|
.entropy_coding_mode_flag = 1,
|
|
.pic_scaling_matrix_present_flag = 0,
|
|
},
|
|
.seq_parameter_set_id = 0,
|
|
.pic_parameter_set_id = 0,
|
|
.num_ref_idx_l0_default_active_minus1 = 0,
|
|
.num_ref_idx_l1_default_active_minus1 = 0,
|
|
.weighted_bipred_idc = STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_DEFAULT,
|
|
.pic_init_qp_minus26 = 0,
|
|
.pic_init_qs_minus26 = 0,
|
|
.chroma_qp_index_offset = 0,
|
|
.second_chroma_qp_index_offset = 0,
|
|
.pScalingLists = NULL,
|
|
};
|
|
|
|
VkVideoDecodeH264SessionParametersAddInfoKHR h264_params = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR,
|
|
.stdSPSCount = 1,
|
|
.pStdSPSs = &h264_std_sps,
|
|
.stdPPSCount = 1,
|
|
.pStdPPSs = &h264_std_pps,
|
|
};
|
|
|
|
GST_START_TEST (test_h264_decoder)
|
|
{
|
|
GstVulkanDecoder *dec;
|
|
GError *err = NULL;
|
|
VkVideoFormatPropertiesKHR format_prop;
|
|
/* *INDENT-OFF* */
|
|
GstVulkanVideoProfile profile = {
|
|
.profile = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR,
|
|
.pNext = &profile.usage,
|
|
.videoCodecOperation = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR,
|
|
.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR,
|
|
.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR,
|
|
.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR,
|
|
},
|
|
.usage.decode = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR,
|
|
.videoUsageHints = VK_VIDEO_DECODE_USAGE_DEFAULT_KHR,
|
|
.pNext = &profile.codec,
|
|
},
|
|
.codec.h264dec = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR,
|
|
.stdProfileIdc = STD_VIDEO_H264_PROFILE_IDC_MAIN,
|
|
.pictureLayout = VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR,
|
|
}
|
|
};
|
|
GstVulkanDecoderParameters create_params = { {
|
|
.sType =
|
|
VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR,
|
|
.maxStdSPSCount = h264_params.stdSPSCount,
|
|
.maxStdPPSCount = h264_params.stdPPSCount,
|
|
.pParametersAddInfo = &h264_params,
|
|
} };
|
|
/* *INDENT-ON* */
|
|
GstVulkanVideoCapabilities video_caps;
|
|
GstVulkanDecoderPicture pic = { NULL, };
|
|
|
|
setup_queue (VK_QUEUE_VIDEO_DECODE_BIT_KHR,
|
|
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR);
|
|
if (!video_queue) {
|
|
GST_WARNING ("Unable to find decoding queue");
|
|
return;
|
|
}
|
|
|
|
dec = gst_vulkan_queue_create_decoder (video_queue,
|
|
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR);
|
|
if (!dec) {
|
|
GST_WARNING ("Unable to create a vulkan decoder");
|
|
return;
|
|
}
|
|
|
|
fail_unless (gst_vulkan_decoder_start (dec, &profile, &err));
|
|
|
|
fail_unless (gst_vulkan_decoder_update_ycbcr_sampler (dec,
|
|
VK_SAMPLER_YCBCR_RANGE_ITU_FULL, VK_CHROMA_LOCATION_COSITED_EVEN,
|
|
VK_CHROMA_LOCATION_MIDPOINT, &err));
|
|
|
|
fail_unless (gst_vulkan_decoder_update_video_session_parameters (dec,
|
|
&create_params, &err));
|
|
|
|
fail_unless (gst_vulkan_decoder_out_format (dec, &format_prop));
|
|
fail_unless (gst_vulkan_decoder_caps (dec, &video_caps));
|
|
|
|
get_output_buffer (dec, format_prop.format, &pic);
|
|
|
|
/* get input buffer */
|
|
{
|
|
static const guint8 slice[] = {
|
|
0x25, 0x88, 0x80, 0x4f, 0xb8, 0x15, 0x59, 0xd0, 0x00, 0x3d, 0xe7, 0xfe,
|
|
0x6e, 0x22, 0xeb, 0xb9,
|
|
0x72, 0x7b, 0x52, 0x8d, 0xd8, 0xf7, 0x14, 0x97, 0xc7, 0xa3, 0x62, 0xb7,
|
|
0x6a, 0x61, 0x8e, 0xd2,
|
|
0xec, 0x64, 0xbc, 0xa4, 0x00, 0x00, 0x05, 0x93, 0xa2, 0x39, 0xa9, 0x99,
|
|
0x1e, 0xc5, 0x01, 0x4a,
|
|
0x00, 0x0c, 0x03, 0x0d, 0x75, 0x45, 0x2a, 0xe3, 0x3d, 0x7f, 0x10, 0x03,
|
|
0x82
|
|
};
|
|
|
|
fail_unless (gst_vulkan_decoder_append_slice (dec, &pic, slice,
|
|
sizeof (slice), TRUE));
|
|
}
|
|
|
|
/* decode */
|
|
{
|
|
StdVideoDecodeH264PictureInfo std_pic = {
|
|
.flags = {
|
|
.field_pic_flag = 0,
|
|
.is_intra = 1,
|
|
.IdrPicFlag = 1,
|
|
.bottom_field_flag = 0,
|
|
.is_reference = 1,
|
|
.complementary_field_pair = 0,
|
|
},
|
|
.seq_parameter_set_id = 0,
|
|
.pic_parameter_set_id = 0,
|
|
.reserved1 = 0,
|
|
.reserved2 = 0,
|
|
.frame_num = 0,
|
|
.idr_pic_id = 0,
|
|
.PicOrderCnt = {0,},
|
|
};
|
|
StdVideoDecodeH264ReferenceInfo std_h264_ref = {
|
|
.flags = {
|
|
.top_field_flag = 0,
|
|
.bottom_field_flag = 0,
|
|
.used_for_long_term_reference = 0,
|
|
.is_non_existing = 0,
|
|
},
|
|
.FrameNum = 0,
|
|
.reserved = 0,
|
|
.PicOrderCnt = {0,},
|
|
};
|
|
VkVideoDecodeH264DpbSlotInfoKHR h264_dpb_slot = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR,
|
|
.pStdReferenceInfo = &std_h264_ref,
|
|
};
|
|
VkVideoDecodeH264PictureInfoKHR vk_pic = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR,
|
|
.pStdPictureInfo = &std_pic,
|
|
.sliceCount = pic.slice_offs->len - 1,
|
|
.pSliceOffsets = (guint32 *) pic.slice_offs->data,
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
pic.pic_res = (VkVideoPictureResourceInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
|
.codedOffset = (VkOffset2D) {0, 0},
|
|
.codedExtent = (VkExtent2D) {320, 240},
|
|
.baseArrayLayer = 0,
|
|
.imageViewBinding = pic.img_view_ref->view,
|
|
};
|
|
pic.slot = (VkVideoReferenceSlotInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR,
|
|
.pNext = &h264_dpb_slot,
|
|
.slotIndex = 0,
|
|
.pPictureResource = &pic.pic_res,
|
|
};
|
|
pic.decode_info = (VkVideoDecodeInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR,
|
|
.pNext = &vk_pic,
|
|
.flags = 0,
|
|
.srcBufferOffset = 0,
|
|
.dstPictureResource = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
|
.codedOffset = (VkOffset2D) {0, 0},
|
|
.codedExtent = (VkExtent2D) {320, 240},
|
|
.baseArrayLayer = 0,
|
|
.imageViewBinding = pic.img_view_out->view,
|
|
},
|
|
.pSetupReferenceSlot = &pic.slot,
|
|
.referenceSlotCount = 0,
|
|
.pReferenceSlots = pic.slots,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
fail_unless (gst_vulkan_decoder_decode (dec, &pic, &err));
|
|
}
|
|
|
|
download_and_check_output_buffer (dec, format_prop.format, &pic);
|
|
|
|
fail_unless (gst_vulkan_decoder_stop (dec));
|
|
|
|
gst_vulkan_decoder_picture_release (&pic);
|
|
|
|
gst_object_unref (dec);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
StdVideoH265HrdParameters h265_std_hrd = { 0, };
|
|
|
|
StdVideoH265ProfileTierLevel h265_std_ptl = {
|
|
.flags = {
|
|
.general_progressive_source_flag = 1,
|
|
.general_frame_only_constraint_flag = 1,
|
|
},
|
|
.general_profile_idc = STD_VIDEO_H265_PROFILE_IDC_MAIN,
|
|
.general_level_idc = STD_VIDEO_H265_LEVEL_IDC_6_0,
|
|
};
|
|
|
|
StdVideoH265DecPicBufMgr h265_std_pbm = {
|
|
.max_latency_increase_plus1 = {5, 0,},
|
|
.max_dec_pic_buffering_minus1 = {4, 0,},
|
|
.max_num_reorder_pics = {2, 0,},
|
|
};
|
|
|
|
StdVideoH265VideoParameterSet h265_std_vps = {
|
|
.flags = {
|
|
.vps_temporal_id_nesting_flag = 1,
|
|
.vps_sub_layer_ordering_info_present_flag = 1,
|
|
},
|
|
.vps_video_parameter_set_id = 0,
|
|
.pDecPicBufMgr = &h265_std_pbm,
|
|
.pHrdParameters = &h265_std_hrd,
|
|
.pProfileTierLevel = &h265_std_ptl,
|
|
};
|
|
|
|
StdVideoH265SequenceParameterSetVui h265_std_sps_vui = {
|
|
.flags = {
|
|
.video_signal_type_present_flag = 1,
|
|
.vui_timing_info_present_flag = 1,
|
|
},
|
|
.aspect_ratio_idc = STD_VIDEO_H265_ASPECT_RATIO_IDC_UNSPECIFIED,
|
|
.video_format = 5,
|
|
.colour_primaries = 2,
|
|
.transfer_characteristics = 2,
|
|
.matrix_coeffs = 2,
|
|
.vui_num_units_in_tick = 1,
|
|
.vui_time_scale = 25,
|
|
.pHrdParameters = &h265_std_hrd,
|
|
};
|
|
|
|
StdVideoH265SequenceParameterSet h265_std_sps = {
|
|
.flags = {
|
|
.sps_temporal_id_nesting_flag = 1,
|
|
.sps_sub_layer_ordering_info_present_flag = 1,
|
|
.sample_adaptive_offset_enabled_flag = 1,
|
|
.sps_temporal_mvp_enabled_flag = 1,
|
|
.strong_intra_smoothing_enabled_flag = 1,
|
|
.vui_parameters_present_flag = 1,
|
|
.sps_extension_present_flag = 1,
|
|
},
|
|
.chroma_format_idc = STD_VIDEO_H265_CHROMA_FORMAT_IDC_420,
|
|
.pic_width_in_luma_samples = 320,
|
|
.pic_height_in_luma_samples = 240,
|
|
.sps_video_parameter_set_id = 0,
|
|
.sps_seq_parameter_set_id = 0,
|
|
.log2_max_pic_order_cnt_lsb_minus4 = 4,
|
|
.log2_diff_max_min_luma_coding_block_size = 3,
|
|
.log2_diff_max_min_luma_transform_block_size = 3,
|
|
.pProfileTierLevel = &h265_std_ptl,
|
|
.pDecPicBufMgr = &h265_std_pbm,
|
|
.pSequenceParameterSetVui = &h265_std_sps_vui,
|
|
};
|
|
|
|
StdVideoH265PictureParameterSet h265_std_pps = {
|
|
.flags = {
|
|
.sign_data_hiding_enabled_flag = 1,
|
|
.cu_qp_delta_enabled_flag = 1,
|
|
.weighted_pred_flag = 1,
|
|
.entropy_coding_sync_enabled_flag = 1,
|
|
.uniform_spacing_flag = 1,
|
|
.loop_filter_across_tiles_enabled_flag = 1,
|
|
.pps_loop_filter_across_slices_enabled_flag = 1,
|
|
},
|
|
.pps_pic_parameter_set_id = 0,
|
|
.pps_seq_parameter_set_id = 0,
|
|
.sps_video_parameter_set_id = 0,
|
|
.diff_cu_qp_delta_depth = 1,
|
|
};
|
|
|
|
VkVideoDecodeH265SessionParametersAddInfoKHR h265_params = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR,
|
|
.stdVPSCount = 1,
|
|
.pStdVPSs = &h265_std_vps,
|
|
.stdSPSCount = 1,
|
|
.pStdSPSs = &h265_std_sps,
|
|
.stdPPSCount = 1,
|
|
.pStdPPSs = &h265_std_pps,
|
|
};
|
|
|
|
GST_START_TEST (test_h265_decoder)
|
|
{
|
|
GstVulkanDecoder *dec;
|
|
GError *err = NULL;
|
|
VkVideoFormatPropertiesKHR format_prop;
|
|
/* *INDENT-OFF* */
|
|
GstVulkanVideoProfile profile = {
|
|
.profile = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR,
|
|
.pNext = &profile.usage,
|
|
.videoCodecOperation = VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR,
|
|
.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR,
|
|
.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR,
|
|
.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR,
|
|
},
|
|
.usage.decode = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR,
|
|
.videoUsageHints = VK_VIDEO_DECODE_USAGE_DEFAULT_KHR,
|
|
.pNext = &profile.codec,
|
|
},
|
|
.codec.h265dec = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR,
|
|
.stdProfileIdc = STD_VIDEO_H265_PROFILE_IDC_MAIN,
|
|
}
|
|
};
|
|
GstVulkanDecoderParameters create_params = {
|
|
.h265 = {
|
|
.sType =
|
|
VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR,
|
|
.maxStdVPSCount = h265_params.stdVPSCount,
|
|
.maxStdSPSCount = h265_params.stdSPSCount,
|
|
.maxStdPPSCount = h265_params.stdPPSCount,
|
|
.pParametersAddInfo = &h265_params,
|
|
}
|
|
};
|
|
/* *INDENT-ON* */
|
|
GstVulkanVideoCapabilities video_caps;
|
|
GstVulkanDecoderPicture pic = { NULL, };
|
|
|
|
setup_queue (VK_QUEUE_VIDEO_DECODE_BIT_KHR,
|
|
VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
|
|
if (!video_queue) {
|
|
GST_WARNING ("Unable to find decoding queue");
|
|
return;
|
|
}
|
|
|
|
dec = gst_vulkan_queue_create_decoder (video_queue,
|
|
VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
|
|
if (!dec) {
|
|
GST_WARNING ("Unable to create a vulkan decoder");
|
|
return;
|
|
}
|
|
|
|
fail_unless (gst_vulkan_decoder_start (dec, &profile, &err));
|
|
|
|
fail_unless (gst_vulkan_decoder_update_ycbcr_sampler (dec,
|
|
VK_SAMPLER_YCBCR_RANGE_ITU_FULL, VK_CHROMA_LOCATION_COSITED_EVEN,
|
|
VK_CHROMA_LOCATION_MIDPOINT, &err));
|
|
|
|
fail_unless (gst_vulkan_decoder_update_video_session_parameters (dec,
|
|
&create_params, &err));
|
|
|
|
fail_unless (gst_vulkan_decoder_out_format (dec, &format_prop));
|
|
fail_unless (gst_vulkan_decoder_caps (dec, &video_caps));
|
|
|
|
get_output_buffer (dec, format_prop.format, &pic);
|
|
|
|
/* get input buffer */
|
|
{
|
|
static const guint8 slice[] = {
|
|
0x28, 0x01, 0xaf, 0x1d, 0x21, 0x6a, 0x83, 0x40, 0xf7, 0xcf, 0x80, 0xff,
|
|
0xf8, 0x90, 0xfa, 0x3b, 0x77, 0x87, 0x96, 0x96, 0xba, 0xfa, 0xcd, 0x61,
|
|
0xb5, 0xe3, 0xc1, 0x02, 0x2d, 0xe0, 0xa8, 0x17, 0x96, 0x03, 0x4c, 0x4e,
|
|
0x1a, 0x9e, 0xd0, 0x93, 0x0b, 0x93, 0x40, 0x00, 0x05, 0xec, 0x87, 0x00,
|
|
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x56, 0x40
|
|
};
|
|
|
|
fail_unless (gst_vulkan_decoder_append_slice (dec, &pic, slice,
|
|
sizeof (slice), TRUE));
|
|
}
|
|
|
|
/* decode */
|
|
{
|
|
StdVideoDecodeH265PictureInfo std_pic = {
|
|
.flags = {
|
|
.IrapPicFlag = 1,
|
|
.IdrPicFlag = 1,
|
|
.IsReference = 1,
|
|
.short_term_ref_pic_set_sps_flag = 0,
|
|
},
|
|
.sps_video_parameter_set_id = 0,
|
|
.pps_seq_parameter_set_id = 0,
|
|
.pps_pic_parameter_set_id = 0,
|
|
.NumDeltaPocsOfRefRpsIdx = 0,
|
|
.PicOrderCntVal = 0,
|
|
.NumBitsForSTRefPicSetInSlice = 0,
|
|
.RefPicSetStCurrBefore =
|
|
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,},
|
|
.RefPicSetStCurrAfter = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,},
|
|
.RefPicSetLtCurr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,},
|
|
};
|
|
StdVideoDecodeH265ReferenceInfo std_h265_ref = {
|
|
.flags = {
|
|
.used_for_long_term_reference = 0,
|
|
.unused_for_reference = 0,
|
|
},
|
|
.PicOrderCntVal = 0,
|
|
};
|
|
VkVideoDecodeH265DpbSlotInfoKHR h265_dpb_slot = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR,
|
|
.pStdReferenceInfo = &std_h265_ref,
|
|
};
|
|
VkVideoDecodeH265PictureInfoKHR vk_pic = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR,
|
|
.pStdPictureInfo = &std_pic,
|
|
.sliceSegmentCount = pic.slice_offs->len - 1,
|
|
.pSliceSegmentOffsets = (guint32 *) pic.slice_offs->data,
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
pic.pic_res = (VkVideoPictureResourceInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
|
.codedOffset = (VkOffset2D) {0, 0},
|
|
.codedExtent = (VkExtent2D) {320, 240},
|
|
.baseArrayLayer = 0,
|
|
.imageViewBinding = pic.img_view_ref->view,
|
|
};
|
|
pic.slot = (VkVideoReferenceSlotInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR,
|
|
.pNext = &h265_dpb_slot,
|
|
.slotIndex = 0,
|
|
.pPictureResource = &pic.pic_res,
|
|
};
|
|
pic.decode_info = (VkVideoDecodeInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR,
|
|
.pNext = &vk_pic,
|
|
.flags = 0,
|
|
.srcBufferOffset = 0,
|
|
.dstPictureResource = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
|
.codedOffset = (VkOffset2D) {0, 0},
|
|
.codedExtent = (VkExtent2D) {320, 240},
|
|
.baseArrayLayer = 0,
|
|
.imageViewBinding = pic.img_view_out->view,
|
|
},
|
|
.pSetupReferenceSlot = &pic.slot,
|
|
.referenceSlotCount = 0,
|
|
.pReferenceSlots = pic.slots,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
fail_unless (gst_vulkan_decoder_decode (dec, &pic, &err));
|
|
}
|
|
|
|
download_and_check_output_buffer (dec, format_prop.format, &pic);
|
|
|
|
fail_unless (gst_vulkan_decoder_stop (dec));
|
|
|
|
gst_vulkan_decoder_picture_release (&pic);
|
|
|
|
gst_object_unref (dec);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
|
|
static Suite *
|
|
vkvideo_suite (void)
|
|
{
|
|
Suite *s = suite_create ("vkvideo");
|
|
TCase *tc_basic = tcase_create ("general");
|
|
gboolean have_instance;
|
|
|
|
suite_add_tcase (s, tc_basic);
|
|
tcase_add_checked_fixture (tc_basic, setup, teardown);
|
|
|
|
/* FIXME: CI doesn't have a software vulkan renderer (and none exists currently) */
|
|
instance = gst_vulkan_instance_new ();
|
|
have_instance = gst_vulkan_instance_open (instance, NULL);
|
|
gst_object_unref (instance);
|
|
if (have_instance) {
|
|
tcase_add_test (tc_basic, test_h264_decoder);
|
|
tcase_add_test (tc_basic, test_h265_decoder);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
GST_CHECK_MAIN (vkvideo);
|