mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-12 03:16:33 +00:00
56ac5e9041
Since a validation layer error is signaled at EOS because it's required to wait for the last frame to be processed. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6534>
1686 lines
59 KiB
C
1686 lines
59 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., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "vkh265dec.h"
|
|
|
|
#include <gst/video/video.h>
|
|
#include <gst/vulkan/vulkan.h>
|
|
|
|
#include "gstvulkanelements.h"
|
|
|
|
typedef struct _GstVulkanH265Decoder GstVulkanH265Decoder;
|
|
typedef struct _GstVulkanH265Picture GstVulkanH265Picture;
|
|
|
|
struct _GstVulkanH265Picture
|
|
{
|
|
GstVulkanDecoderPicture base;
|
|
|
|
/* 16 is max DPB size */
|
|
/* Picture refs */
|
|
StdVideoDecodeH265ReferenceInfo std_refs[16];
|
|
VkVideoDecodeH265DpbSlotInfoKHR vk_slots[16];
|
|
|
|
/* Current picture */
|
|
StdVideoDecodeH265ReferenceInfo std_ref;
|
|
VkVideoDecodeH265DpbSlotInfoKHR vk_slot;
|
|
|
|
VkVideoDecodeH265PictureInfoKHR vk_h265pic;
|
|
StdVideoDecodeH265PictureInfo std_h265pic;
|
|
|
|
gint32 slot_idx;
|
|
};
|
|
|
|
struct _GstVulkanH265Decoder
|
|
{
|
|
GstH265Decoder parent;
|
|
|
|
GstVulkanInstance *instance;
|
|
GstVulkanDevice *device;
|
|
GstVulkanQueue *graphic_queue, *decode_queue;
|
|
|
|
GstVulkanDecoder *decoder;
|
|
|
|
gboolean need_negotiation;
|
|
gboolean need_params_update;
|
|
|
|
gint x, y;
|
|
gint width, height;
|
|
gint coded_width, coded_height;
|
|
gint dpb_size;
|
|
|
|
VkSamplerYcbcrRange range;
|
|
VkChromaLocation xloc, yloc;
|
|
|
|
GstVideoCodecState *output_state;
|
|
};
|
|
|
|
static GstStaticPadTemplate gst_vulkan_h265dec_sink_template =
|
|
GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("video/x-h265, "
|
|
"profile = (string) main,"
|
|
"stream-format = { (string) hvc1, (string) hev1, (string) byte-stream }, "
|
|
"alignment = (string) au"));
|
|
|
|
static GstStaticPadTemplate gst_vulkan_h265dec_src_template =
|
|
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
|
|
(GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE, "NV12")));
|
|
|
|
GST_DEBUG_CATEGORY (gst_debug_vulkan_h265_decoder);
|
|
#define GST_CAT_DEFAULT gst_debug_vulkan_h265_decoder
|
|
|
|
#define gst_vulkan_h265_decoder_parent_class parent_class
|
|
G_DEFINE_TYPE_WITH_CODE (GstVulkanH265Decoder, gst_vulkan_h265_decoder,
|
|
GST_TYPE_H265_DECODER,
|
|
GST_DEBUG_CATEGORY_INIT (gst_debug_vulkan_h265_decoder,
|
|
"vulkanh265dec", 0, "Vulkan H.265 Decoder"));
|
|
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (vulkanh265dec, "vulkanh265dec",
|
|
GST_RANK_NONE, GST_TYPE_VULKAN_H265_DECODER, vulkan_element_init (plugin));
|
|
|
|
static void
|
|
gst_vulkan_h265_decoder_set_context (GstElement * element, GstContext * context)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (element);
|
|
|
|
gst_vulkan_handle_set_context (element, context, NULL, &self->instance);
|
|
|
|
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
|
|
}
|
|
|
|
static gboolean
|
|
_query_context (GstVulkanH265Decoder * self, GstQuery * query)
|
|
{
|
|
if (gst_vulkan_handle_context_query (GST_ELEMENT (self), query, NULL,
|
|
self->instance, self->device))
|
|
return TRUE;
|
|
|
|
if (gst_vulkan_queue_handle_context_query (GST_ELEMENT (self), query,
|
|
self->graphic_queue))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gst_vulkan_h265_decoder_src_query (GstVideoDecoder * decoder, GstQuery * query)
|
|
{
|
|
gboolean ret = FALSE;
|
|
|
|
switch (GST_QUERY_TYPE (query)) {
|
|
case GST_QUERY_CONTEXT:
|
|
ret = _query_context (GST_VULKAN_H265_DECODER (decoder), query);
|
|
break;
|
|
default:
|
|
ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (decoder, query);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
gst_vulkan_h265_decoder_sink_query (GstVideoDecoder * decoder, GstQuery * query)
|
|
{
|
|
gboolean ret = FALSE;
|
|
|
|
switch (GST_QUERY_TYPE (query)) {
|
|
case GST_QUERY_CONTEXT:
|
|
ret = _query_context (GST_VULKAN_H265_DECODER (decoder), query);
|
|
break;
|
|
default:
|
|
ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (decoder, query);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
_find_queues (GstVulkanDevice * device, GstVulkanQueue * queue, gpointer data)
|
|
{
|
|
GstVulkanH265Decoder *self = data;
|
|
guint32 flags =
|
|
device->physical_device->queue_family_props[queue->family].queueFlags;
|
|
guint32 codec =
|
|
device->physical_device->queue_family_ops[queue->family].video;
|
|
|
|
if (!self->graphic_queue
|
|
&& ((flags & VK_QUEUE_GRAPHICS_BIT) == VK_QUEUE_GRAPHICS_BIT)) {
|
|
self->graphic_queue = gst_object_ref (queue);
|
|
}
|
|
|
|
if (!self->decode_queue
|
|
&& ((codec & VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR)
|
|
== VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR)
|
|
&& ((flags & VK_QUEUE_VIDEO_DECODE_BIT_KHR)
|
|
== VK_QUEUE_VIDEO_DECODE_BIT_KHR)) {
|
|
self->decode_queue = gst_object_ref (queue);
|
|
}
|
|
|
|
return !(self->decode_queue && self->graphic_queue);
|
|
}
|
|
|
|
static gboolean
|
|
gst_vulkan_h265_decoder_open (GstVideoDecoder * decoder)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
|
|
if (!gst_vulkan_ensure_element_data (GST_ELEMENT (decoder), NULL,
|
|
&self->instance)) {
|
|
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
|
("Failed to retrieve vulkan instance"), (NULL));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gst_vulkan_device_run_context_query (GST_ELEMENT (decoder),
|
|
&self->device)) {
|
|
GError *error = NULL;
|
|
GST_DEBUG_OBJECT (self, "No device retrieved from peer elements");
|
|
self->device = gst_vulkan_instance_create_device (self->instance, &error);
|
|
if (!self->device) {
|
|
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
|
("Failed to create vulkan device"),
|
|
("%s", error ? error->message : ""));
|
|
g_clear_error (&error);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!gst_vulkan_queue_run_context_query (GST_ELEMENT (self),
|
|
&self->graphic_queue)) {
|
|
GST_DEBUG_OBJECT (self, "No graphic queue retrieved from peer elements");
|
|
}
|
|
|
|
gst_vulkan_device_foreach_queue (self->device, _find_queues, self);
|
|
|
|
if (!self->decode_queue) {
|
|
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
|
("Failed to create/retrieve vulkan H.264 decoder queue"), (NULL));
|
|
return FALSE;
|
|
}
|
|
|
|
self->decoder = gst_vulkan_queue_create_decoder (self->decode_queue,
|
|
VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
|
|
if (!self->decoder) {
|
|
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
|
("Failed to create vulkan H.264 decoder"), (NULL));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gst_vulkan_h265_decoder_close (GstVideoDecoder * decoder)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
|
|
gst_clear_object (&self->decoder);
|
|
gst_clear_object (&self->decode_queue);
|
|
gst_clear_object (&self->graphic_queue);
|
|
gst_clear_object (&self->device);
|
|
gst_clear_object (&self->instance);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gst_vulkan_h265_decoder_stop (GstVideoDecoder * decoder)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
|
|
if (self->decoder)
|
|
gst_vulkan_decoder_stop (self->decoder);
|
|
|
|
if (self->output_state)
|
|
gst_video_codec_state_unref (self->output_state);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gst_vulkan_h265_decoder_negotiate (GstVideoDecoder * decoder)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
|
|
VkVideoFormatPropertiesKHR format_prop;
|
|
GstVideoFormat format;
|
|
|
|
/* Ignore downstream renegotiation request. */
|
|
if (!self->need_negotiation)
|
|
return TRUE;
|
|
|
|
if (!gst_vulkan_decoder_out_format (self->decoder, &format_prop))
|
|
return FALSE;
|
|
|
|
self->need_negotiation = FALSE;
|
|
|
|
if (self->output_state)
|
|
gst_video_codec_state_unref (self->output_state);
|
|
|
|
format = gst_vulkan_format_to_video_format (format_prop.format);
|
|
self->output_state = gst_video_decoder_set_interlaced_output_state (decoder,
|
|
format, GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, self->width, self->height,
|
|
h265dec->input_state);
|
|
|
|
self->output_state->caps = gst_video_info_to_caps (&self->output_state->info);
|
|
gst_caps_set_features_simple (self->output_state->caps,
|
|
gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE, NULL));
|
|
|
|
GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
|
|
self->output_state->caps);
|
|
|
|
return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
|
|
}
|
|
|
|
static gboolean
|
|
gst_vulkan_h265_decoder_decide_allocation (GstVideoDecoder * decoder,
|
|
GstQuery * query)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
GstCaps *new_caps, *profile_caps, *caps = NULL;
|
|
GstBufferPool *pool = NULL;
|
|
GstStructure *config;
|
|
guint size, min, max;
|
|
gboolean update_pool;
|
|
VkImageUsageFlags usage;
|
|
GstVulkanVideoCapabilities vk_caps;
|
|
|
|
gst_query_parse_allocation (query, &caps, NULL);
|
|
if (!caps)
|
|
return FALSE;
|
|
if (!gst_vulkan_decoder_caps (self->decoder, &vk_caps))
|
|
return FALSE;
|
|
|
|
if (gst_query_get_n_allocation_pools (query) > 0) {
|
|
gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
|
|
update_pool = TRUE;
|
|
} else {
|
|
GstVideoInfo vinfo;
|
|
|
|
gst_video_info_from_caps (&vinfo, caps);
|
|
size = GST_VIDEO_INFO_SIZE (&vinfo);
|
|
min = 2;
|
|
max = 0;
|
|
update_pool = FALSE;
|
|
}
|
|
|
|
if (!(pool && GST_IS_VULKAN_IMAGE_BUFFER_POOL (pool))) {
|
|
gst_clear_object (&pool);
|
|
pool = gst_vulkan_image_buffer_pool_new (self->device);
|
|
}
|
|
|
|
usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
|
| VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR;
|
|
|
|
if (!self->decoder->dedicated_dpb) {
|
|
min = MAX (min, MIN (self->dpb_size, vk_caps.caps.maxDpbSlots));
|
|
max = 0;
|
|
usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
|
|
}
|
|
|
|
new_caps = gst_caps_copy (caps);
|
|
gst_caps_set_simple (new_caps, "width", G_TYPE_INT, self->coded_width,
|
|
"height", G_TYPE_INT, self->coded_height, NULL);
|
|
profile_caps = gst_vulkan_decoder_profile_caps (self->decoder);
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
|
|
gst_buffer_pool_config_set_params (config, new_caps, size, min, max);
|
|
|
|
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);
|
|
gst_caps_unref (new_caps);
|
|
|
|
if (!gst_buffer_pool_set_config (pool, config))
|
|
goto bail;
|
|
|
|
if (update_pool)
|
|
gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
|
|
else
|
|
gst_query_add_allocation_pool (query, pool, size, min, max);
|
|
|
|
gst_object_unref (pool);
|
|
|
|
gst_vulkan_decoder_create_dpb_pool (self->decoder, new_caps);
|
|
|
|
return TRUE;
|
|
|
|
bail:
|
|
{
|
|
gst_clear_caps (&new_caps);
|
|
gst_clear_object (&pool);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* FIXME: dup with h264 */
|
|
static VkVideoChromaSubsamplingFlagBitsKHR
|
|
_get_chroma_subsampling_flag (guint8 chroma_format_idc)
|
|
{
|
|
switch (chroma_format_idc) {
|
|
case 1:
|
|
return VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR;
|
|
case 2:
|
|
return VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR;
|
|
case 3:
|
|
return VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR;
|
|
default:
|
|
return VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_KHR;
|
|
}
|
|
}
|
|
|
|
/* FIXME: dup with h264 */
|
|
static VkVideoComponentBitDepthFlagBitsKHR
|
|
_get_component_bit_depth (guint8 bit_depth)
|
|
{
|
|
switch (bit_depth) {
|
|
case 8:
|
|
return VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
|
|
case 10:
|
|
return VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
|
|
case 12:
|
|
return VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
|
|
default:
|
|
return VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR;
|
|
}
|
|
}
|
|
|
|
static StdVideoH265ProfileIdc
|
|
_get_h265_profile (GstH265Profile profile_idc)
|
|
{
|
|
switch (profile_idc) {
|
|
case GST_H265_PROFILE_MAIN:
|
|
return STD_VIDEO_H265_PROFILE_IDC_MAIN;
|
|
case GST_H265_PROFILE_MAIN_10:
|
|
return STD_VIDEO_H265_PROFILE_IDC_MAIN_10;
|
|
case GST_H265_PROFILE_MAIN_STILL_PICTURE:
|
|
return STD_VIDEO_H265_PROFILE_IDC_MAIN_STILL_PICTURE;
|
|
/* FIXME */
|
|
/* case GST_H265_PROFILE_XXX: */
|
|
/* return STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS; */
|
|
case GST_H265_PROFILE_SCALABLE_MAIN:
|
|
return STD_VIDEO_H265_PROFILE_IDC_SCC_EXTENSIONS;
|
|
default:
|
|
return STD_VIDEO_H265_PROFILE_IDC_INVALID;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_vulkan_video_profile_from_h265_sps (GstVulkanVideoProfile * profile,
|
|
const GstH265SPS * sps)
|
|
{
|
|
/* *INDENT-OFF* */
|
|
*profile = (GstVulkanVideoProfile) {
|
|
.profile = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR,
|
|
.pNext = &profile->usage,
|
|
.videoCodecOperation = VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR,
|
|
.chromaSubsampling = _get_chroma_subsampling_flag (sps->chroma_format_idc),
|
|
.lumaBitDepth = _get_component_bit_depth (sps->bit_depth_luma_minus8 + 8),
|
|
.chromaBitDepth = _get_component_bit_depth (sps->bit_depth_chroma_minus8 + 8),
|
|
},
|
|
.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 =
|
|
_get_h265_profile (gst_h265_get_profile_from_sps ((GstH265SPS *) sps)),
|
|
},
|
|
};
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_vulkan_h265_decoder_new_sequence (GstH265Decoder * decoder,
|
|
const GstH265SPS * sps, gint max_dpb_size)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
GstVulkanVideoProfile profile;
|
|
GstVulkanVideoCapabilities vk_caps;
|
|
GError *error = NULL;
|
|
gint x, y, width, height;
|
|
VkFormat old_format = VK_FORMAT_UNDEFINED;
|
|
VkVideoFormatPropertiesKHR format_prop;
|
|
|
|
gst_vulkan_video_profile_from_h265_sps (&profile, sps);
|
|
|
|
if (gst_vulkan_decoder_is_started (self->decoder)) {
|
|
if (!gst_vulkan_video_profile_is_equal (&self->decoder->profile, &profile)) {
|
|
if (gst_vulkan_decoder_out_format (self->decoder, &format_prop))
|
|
old_format = format_prop.format;
|
|
gst_vulkan_decoder_stop (self->decoder);
|
|
} else {
|
|
self->need_negotiation = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!gst_vulkan_decoder_is_started (self->decoder)) {
|
|
self->need_negotiation = TRUE;
|
|
if (!gst_vulkan_decoder_start (self->decoder, &profile, &error)) {
|
|
GST_ERROR_OBJECT (self, "Couldn't start decoder: %s",
|
|
error ? error->message : "");
|
|
g_clear_error (&error);
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
}
|
|
|
|
self->dpb_size = MAX (self->dpb_size, max_dpb_size);
|
|
|
|
if (sps->conformance_window_flag) {
|
|
x = sps->crop_rect_x;
|
|
y = sps->crop_rect_y;
|
|
width = sps->crop_rect_width;
|
|
height = sps->crop_rect_height;
|
|
} else {
|
|
width = sps->width;
|
|
height = sps->height;
|
|
x = y = 0;
|
|
}
|
|
|
|
gst_vulkan_decoder_caps (self->decoder, &vk_caps);
|
|
self->coded_width =
|
|
GST_ROUND_UP_N (sps->width, vk_caps.caps.pictureAccessGranularity.width);
|
|
self->coded_height = GST_ROUND_UP_N (sps->height,
|
|
vk_caps.caps.pictureAccessGranularity.height);
|
|
|
|
self->need_negotiation &= (x != self->x || y != self->y
|
|
|| width != self->width || height != self->height);
|
|
self->x = x;
|
|
self->y = y;
|
|
self->width = width;
|
|
self->height = height;
|
|
|
|
/* Ycbcr sampler */
|
|
{
|
|
VkSamplerYcbcrRange range;
|
|
VkChromaLocation xloc, yloc;
|
|
gboolean ret;
|
|
int loc;
|
|
|
|
ret = gst_vulkan_decoder_out_format (self->decoder, &format_prop);
|
|
g_assert (ret);
|
|
|
|
range = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
|
|
loc = 0;
|
|
|
|
if (sps->vui_parameters_present_flag) {
|
|
const GstH265VUIParams *vui = &sps->vui_params;
|
|
|
|
range = vui->video_full_range_flag > 0 ?
|
|
VK_SAMPLER_YCBCR_RANGE_ITU_FULL : VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
|
|
|
|
if (vui->chroma_loc_info_present_flag)
|
|
loc = vui->chroma_sample_loc_type_top_field;
|
|
}
|
|
|
|
xloc = (loc % 2 == 0) ? VK_CHROMA_LOCATION_MIDPOINT
|
|
: VK_CHROMA_LOCATION_COSITED_EVEN;
|
|
yloc = ((loc >> 1) ^ (loc < 4)) ? VK_CHROMA_LOCATION_MIDPOINT
|
|
: VK_CHROMA_LOCATION_COSITED_EVEN;
|
|
|
|
if (old_format != format_prop.format || range != self->range
|
|
|| xloc != self->xloc || yloc != self->yloc) {
|
|
self->range = range;
|
|
self->xloc = xloc;
|
|
self->yloc = yloc;
|
|
ret = gst_vulkan_decoder_update_ycbcr_sampler (self->decoder, range, xloc,
|
|
yloc, &error);
|
|
if (!ret && error) {
|
|
GST_WARNING_OBJECT (self, "Unable to create Ycbcr sampler: %s",
|
|
error->message);
|
|
g_clear_error (&error);
|
|
}
|
|
}
|
|
}
|
|
|
|
self->need_params_update = TRUE;
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
/* set a common pipeline stage valid for any queue to avoid Vulkan Validation
|
|
* errors */
|
|
static void
|
|
reset_pipeline_stage_mask (GstBuffer * buf)
|
|
{
|
|
guint i, n = gst_buffer_n_memory (buf);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
GstVulkanImageMemory *vk_mem =
|
|
(GstVulkanImageMemory *) gst_buffer_peek_memory (buf, i);
|
|
vk_mem->barrier.parent.pipeline_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
|
}
|
|
}
|
|
|
|
static GstVulkanH265Picture *
|
|
gst_vulkan_h265_picture_new (GstVulkanH265Decoder * self, GstBuffer * out)
|
|
{
|
|
GstVulkanH265Picture *pic;
|
|
|
|
pic = g_new0 (GstVulkanH265Picture, 1);
|
|
gst_vulkan_decoder_picture_init (self->decoder, &pic->base, out);
|
|
reset_pipeline_stage_mask (out);
|
|
|
|
return pic;
|
|
}
|
|
|
|
static void
|
|
gst_vulkan_h265_picture_free (gpointer data)
|
|
{
|
|
GstVulkanH265Picture *pic = data;
|
|
|
|
gst_vulkan_decoder_picture_release (&pic->base);
|
|
g_free (pic);
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_vulkan_h265_decoder_new_picture (GstH265Decoder * decoder,
|
|
GstVideoCodecFrame * frame, GstH265Picture * picture)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
|
|
GstFlowReturn ret;
|
|
GstVulkanH265Picture *pic;
|
|
|
|
GST_TRACE_OBJECT (self, "New picture");
|
|
|
|
if (self->need_negotiation) {
|
|
if (!gst_video_decoder_negotiate (vdec)) {
|
|
GST_ERROR_OBJECT (self, "Failed downstream negotiation.");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
}
|
|
|
|
ret = gst_video_decoder_allocate_output_frame (vdec, frame);
|
|
if (ret != GST_FLOW_OK)
|
|
goto allocation_failed;
|
|
|
|
pic = gst_vulkan_h265_picture_new (self, frame->output_buffer);
|
|
gst_h265_picture_set_user_data (picture, pic, gst_vulkan_h265_picture_free);
|
|
|
|
return GST_FLOW_OK;
|
|
|
|
allocation_failed:
|
|
{
|
|
GST_WARNING_OBJECT (self, "Failed to allocated input or output buffer: %s",
|
|
gst_flow_get_name (ret));
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
struct SPS
|
|
{
|
|
StdVideoH265SequenceParameterSet sps;
|
|
StdVideoH265ScalingLists scaling;
|
|
StdVideoH265HrdParameters vui_header;
|
|
StdVideoH265SequenceParameterSetVui vui;
|
|
StdVideoH265ProfileTierLevel ptl;
|
|
StdVideoH265DecPicBufMgr dpbm;
|
|
StdVideoH265PredictorPaletteEntries pal;
|
|
StdVideoH265SubLayerHrdParameters nal_hrd[GST_H265_MAX_SUB_LAYERS];
|
|
StdVideoH265SubLayerHrdParameters vcl_hrd[GST_H265_MAX_SUB_LAYERS];
|
|
/* 7.4.3.2.1: num_short_term_ref_pic_sets is in [0, 64]. */
|
|
StdVideoH265ShortTermRefPicSet str[64];
|
|
StdVideoH265LongTermRefPicsSps ltr;
|
|
};
|
|
|
|
struct PPS
|
|
{
|
|
StdVideoH265PictureParameterSet pps;
|
|
StdVideoH265ScalingLists scaling;
|
|
StdVideoH265PredictorPaletteEntries pal;
|
|
};
|
|
|
|
struct VPS
|
|
{
|
|
StdVideoH265VideoParameterSet vps;
|
|
StdVideoH265ProfileTierLevel ptl;
|
|
StdVideoH265DecPicBufMgr dpbm;
|
|
/* FIXME: a VPS can have multiple header params, each with its own nal and vlc
|
|
headers sets. Sadly, that's not currently supported by the GStreamer H265
|
|
parser, which only supports one header params per VPS. */
|
|
StdVideoH265HrdParameters hrd;
|
|
StdVideoH265SubLayerHrdParameters nal_hdr[GST_H265_MAX_SUB_LAYERS];
|
|
StdVideoH265SubLayerHrdParameters vcl_hdr[GST_H265_MAX_SUB_LAYERS];
|
|
};
|
|
|
|
static void
|
|
_copy_scaling_list (const GstH265ScalingList * scaling_list,
|
|
StdVideoH265ScalingLists * vk_scaling_lists)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < STD_VIDEO_H265_SCALING_LIST_4X4_NUM_LISTS; i++) {
|
|
gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
|
|
(vk_scaling_lists->ScalingList4x4[i],
|
|
scaling_list->scaling_lists_4x4[i]);
|
|
}
|
|
|
|
for (i = 0; i < STD_VIDEO_H265_SCALING_LIST_8X8_NUM_LISTS; i++) {
|
|
gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
|
|
(vk_scaling_lists->ScalingList8x8[i],
|
|
scaling_list->scaling_lists_8x8[i]);
|
|
}
|
|
|
|
for (i = 0; i < STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS; i++) {
|
|
gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
|
|
(vk_scaling_lists->ScalingList16x16[i],
|
|
scaling_list->scaling_lists_16x16[i]);
|
|
}
|
|
|
|
for (i = 0; i < STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS; i++) {
|
|
gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
|
|
(vk_scaling_lists->ScalingList32x32[i],
|
|
scaling_list->scaling_lists_32x32[i]);
|
|
}
|
|
|
|
for (i = 0; i < STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS; i++) {
|
|
vk_scaling_lists->ScalingListDCCoef16x16[i] =
|
|
scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
|
|
}
|
|
|
|
for (i = 0; i < STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS; i++) {
|
|
vk_scaling_lists->ScalingListDCCoef32x32[i] =
|
|
scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
|
|
}
|
|
}
|
|
|
|
static guint32
|
|
_array_2_bitmask (const guint8 * array, guint8 size)
|
|
{
|
|
guint8 i;
|
|
guint32 bitmask = 0;
|
|
|
|
for (i = 0; i < MIN (size, 32); i++)
|
|
bitmask |= !!array[i] << i;
|
|
return bitmask;
|
|
}
|
|
|
|
static StdVideoH265LevelIdc
|
|
_get_h265_level_idc (int level_idc)
|
|
{
|
|
switch (level_idc) {
|
|
case 10:
|
|
return STD_VIDEO_H265_LEVEL_IDC_1_0;
|
|
case 20:
|
|
return STD_VIDEO_H265_LEVEL_IDC_2_0;
|
|
case 21:
|
|
return STD_VIDEO_H265_LEVEL_IDC_2_1;
|
|
case 30:
|
|
return STD_VIDEO_H265_LEVEL_IDC_3_0;
|
|
case 31:
|
|
return STD_VIDEO_H265_LEVEL_IDC_3_1;
|
|
case 40:
|
|
return STD_VIDEO_H265_LEVEL_IDC_4_0;
|
|
case 41:
|
|
return STD_VIDEO_H265_LEVEL_IDC_4_1;
|
|
case 50:
|
|
return STD_VIDEO_H265_LEVEL_IDC_5_0;
|
|
case 51:
|
|
return STD_VIDEO_H265_LEVEL_IDC_5_1;
|
|
case 52:
|
|
return STD_VIDEO_H265_LEVEL_IDC_5_2;
|
|
case 60:
|
|
return STD_VIDEO_H265_LEVEL_IDC_6_0;
|
|
case 61:
|
|
return STD_VIDEO_H265_LEVEL_IDC_6_1;
|
|
default:
|
|
case 62:
|
|
return STD_VIDEO_H265_LEVEL_IDC_6_2;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_copy_sub_layers_hrd_params (const GstH265SubLayerHRDParams * params,
|
|
StdVideoH265SubLayerHrdParameters * vkparams, int num_params)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num_params; i++) {
|
|
memcpy (vkparams[i].bit_rate_du_value_minus1,
|
|
params[i].bit_rate_du_value_minus1, STD_VIDEO_H265_CPB_CNT_LIST_SIZE
|
|
* sizeof (*vkparams[i].bit_rate_du_value_minus1));
|
|
memcpy (vkparams[i].bit_rate_value_minus1, params[i].bit_rate_value_minus1,
|
|
STD_VIDEO_H265_CPB_CNT_LIST_SIZE
|
|
* sizeof (*vkparams[i].bit_rate_value_minus1));
|
|
memcpy (vkparams[i].cpb_size_value_minus1, params[i].cpb_size_value_minus1,
|
|
STD_VIDEO_H265_CPB_CNT_LIST_SIZE
|
|
* sizeof (*vkparams[i].cpb_size_value_minus1));
|
|
memcpy (vkparams[i].cpb_size_du_value_minus1,
|
|
params[i].cpb_size_du_value_minus1, STD_VIDEO_H265_CPB_CNT_LIST_SIZE
|
|
* sizeof (*vkparams[i].cpb_size_du_value_minus1));
|
|
|
|
vkparams[i].cbr_flag =
|
|
_array_2_bitmask (params[i].cbr_flag, STD_VIDEO_H265_CPB_CNT_LIST_SIZE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_copy_profile_tier_level (const GstH265ProfileTierLevel * ptl,
|
|
StdVideoH265ProfileTierLevel * vk_ptl)
|
|
{
|
|
/* *INDENT-OFF* */
|
|
*vk_ptl = (StdVideoH265ProfileTierLevel) {
|
|
.flags = {
|
|
.general_tier_flag = ptl->tier_flag,
|
|
.general_progressive_source_flag = ptl->progressive_source_flag,
|
|
.general_interlaced_source_flag = ptl->interlaced_source_flag,
|
|
.general_non_packed_constraint_flag = ptl->non_packed_constraint_flag,
|
|
.general_frame_only_constraint_flag = ptl->frame_only_constraint_flag,
|
|
},
|
|
.general_profile_idc = _get_h265_profile (ptl->profile_idc),
|
|
.general_level_idc = _get_h265_level_idc (ptl->level_idc),
|
|
};
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
static void
|
|
_fill_sps (const GstH265SPS * sps, struct SPS *std_sps)
|
|
{
|
|
int i;
|
|
const GstH265VUIParams *vui_params = &sps->vui_params;
|
|
|
|
_copy_scaling_list (&sps->scaling_list, &std_sps->scaling);
|
|
|
|
if (vui_params->hrd_params.nal_hrd_parameters_present_flag) {
|
|
_copy_sub_layers_hrd_params (vui_params->hrd_params.sublayer_hrd_params,
|
|
std_sps->nal_hrd, STD_VIDEO_H265_SUBLAYERS_LIST_SIZE);
|
|
}
|
|
if (vui_params->hrd_params.vcl_hrd_parameters_present_flag) {
|
|
_copy_sub_layers_hrd_params (vui_params->hrd_params.sublayer_hrd_params,
|
|
std_sps->vcl_hrd, STD_VIDEO_H265_SUBLAYERS_LIST_SIZE);
|
|
}
|
|
std_sps->vui_header = (StdVideoH265HrdParameters) {
|
|
/* *INDENT-OFF* */
|
|
.flags = {
|
|
.nal_hrd_parameters_present_flag =
|
|
vui_params->hrd_params.nal_hrd_parameters_present_flag,
|
|
.vcl_hrd_parameters_present_flag =
|
|
vui_params->hrd_params.vcl_hrd_parameters_present_flag,
|
|
.sub_pic_hrd_params_present_flag =
|
|
vui_params->hrd_params.sub_pic_hrd_params_present_flag,
|
|
.sub_pic_cpb_params_in_pic_timing_sei_flag =
|
|
vui_params->hrd_params.sub_pic_cpb_params_in_pic_timing_sei_flag,
|
|
.fixed_pic_rate_general_flag =
|
|
_array_2_bitmask (vui_params->hrd_params.fixed_pic_rate_general_flag,
|
|
sizeof (vui_params->hrd_params.fixed_pic_rate_general_flag)),
|
|
.fixed_pic_rate_within_cvs_flag =
|
|
_array_2_bitmask (vui_params->hrd_params.fixed_pic_rate_within_cvs_flag,
|
|
sizeof (vui_params->hrd_params.fixed_pic_rate_within_cvs_flag)),
|
|
.low_delay_hrd_flag =
|
|
_array_2_bitmask (vui_params->hrd_params.low_delay_hrd_flag,
|
|
sizeof (vui_params->hrd_params.low_delay_hrd_flag)),
|
|
},
|
|
.tick_divisor_minus2 = vui_params->hrd_params.tick_divisor_minus2,
|
|
.du_cpb_removal_delay_increment_length_minus1 =
|
|
vui_params->hrd_params.du_cpb_removal_delay_increment_length_minus1,
|
|
.dpb_output_delay_du_length_minus1 =
|
|
vui_params->hrd_params.dpb_output_delay_du_length_minus1,
|
|
.bit_rate_scale = vui_params->hrd_params.bit_rate_scale,
|
|
.cpb_size_scale = vui_params->hrd_params.cpb_size_scale,
|
|
.cpb_size_du_scale = vui_params->hrd_params.cpb_size_du_scale,
|
|
.initial_cpb_removal_delay_length_minus1 =
|
|
vui_params->hrd_params.initial_cpb_removal_delay_length_minus1,
|
|
.au_cpb_removal_delay_length_minus1 =
|
|
vui_params->hrd_params.au_cpb_removal_delay_length_minus1,
|
|
.dpb_output_delay_length_minus1 =
|
|
vui_params->hrd_params.dpb_output_delay_length_minus1,
|
|
.pSubLayerHrdParametersNal =
|
|
(const StdVideoH265SubLayerHrdParameters *) &std_sps->nal_hrd,
|
|
.pSubLayerHrdParametersVcl =
|
|
(const StdVideoH265SubLayerHrdParameters *) &std_sps->vcl_hrd,
|
|
/* *INDENT-ON* */
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
std_sps->vui = (StdVideoH265SequenceParameterSetVui) {
|
|
.flags = {
|
|
.aspect_ratio_info_present_flag =
|
|
vui_params->aspect_ratio_info_present_flag,
|
|
.overscan_info_present_flag = vui_params->overscan_info_present_flag,
|
|
.overscan_appropriate_flag = vui_params->overscan_appropriate_flag,
|
|
.video_signal_type_present_flag =
|
|
vui_params->video_signal_type_present_flag,
|
|
.video_full_range_flag = vui_params->video_full_range_flag,
|
|
.colour_description_present_flag =
|
|
vui_params->colour_description_present_flag,
|
|
.chroma_loc_info_present_flag = vui_params->chroma_loc_info_present_flag,
|
|
.neutral_chroma_indication_flag =
|
|
vui_params->neutral_chroma_indication_flag,
|
|
.field_seq_flag = vui_params->field_seq_flag,
|
|
.frame_field_info_present_flag =
|
|
vui_params->frame_field_info_present_flag,
|
|
.default_display_window_flag = vui_params->default_display_window_flag,
|
|
.vui_timing_info_present_flag = vui_params->timing_info_present_flag,
|
|
.vui_poc_proportional_to_timing_flag =
|
|
vui_params->poc_proportional_to_timing_flag,
|
|
.vui_hrd_parameters_present_flag =
|
|
vui_params->hrd_parameters_present_flag,
|
|
.bitstream_restriction_flag = vui_params->bitstream_restriction_flag,
|
|
.tiles_fixed_structure_flag = vui_params->tiles_fixed_structure_flag,
|
|
.motion_vectors_over_pic_boundaries_flag =
|
|
vui_params->motion_vectors_over_pic_boundaries_flag,
|
|
.restricted_ref_pic_lists_flag =
|
|
vui_params->restricted_ref_pic_lists_flag,
|
|
},
|
|
.aspect_ratio_idc = vui_params->aspect_ratio_idc,
|
|
.sar_width = vui_params->sar_width,
|
|
.sar_height = vui_params->sar_height,
|
|
.video_format = vui_params->video_format,
|
|
.colour_primaries = vui_params->colour_primaries,
|
|
.transfer_characteristics = vui_params->transfer_characteristics,
|
|
.matrix_coeffs = vui_params->matrix_coefficients,
|
|
.chroma_sample_loc_type_top_field =
|
|
vui_params->chroma_sample_loc_type_top_field,
|
|
.chroma_sample_loc_type_bottom_field =
|
|
vui_params->chroma_sample_loc_type_bottom_field,
|
|
/* Reserved */
|
|
/* Reserved */
|
|
.def_disp_win_left_offset = vui_params->def_disp_win_left_offset,
|
|
.def_disp_win_right_offset = vui_params->def_disp_win_right_offset,
|
|
.def_disp_win_top_offset = vui_params->def_disp_win_top_offset,
|
|
.def_disp_win_bottom_offset = vui_params->def_disp_win_bottom_offset,
|
|
.vui_num_units_in_tick = vui_params->num_units_in_tick,
|
|
.vui_time_scale = vui_params->time_scale,
|
|
.vui_num_ticks_poc_diff_one_minus1 =
|
|
vui_params->num_ticks_poc_diff_one_minus1,
|
|
.min_spatial_segmentation_idc = vui_params->min_spatial_segmentation_idc,
|
|
.max_bytes_per_pic_denom = vui_params->max_bytes_per_pic_denom,
|
|
.max_bits_per_min_cu_denom = vui_params->max_bits_per_min_cu_denom,
|
|
.log2_max_mv_length_horizontal = vui_params->log2_max_mv_length_horizontal,
|
|
.log2_max_mv_length_vertical = vui_params->log2_max_mv_length_vertical,
|
|
.pHrdParameters = &std_sps->vui_header,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
_copy_profile_tier_level (&sps->profile_tier_level, &std_sps->ptl);
|
|
|
|
memcpy (std_sps->dpbm.max_latency_increase_plus1,
|
|
sps->max_latency_increase_plus1, GST_H265_MAX_SUB_LAYERS
|
|
* sizeof (*std_sps->dpbm.max_latency_increase_plus1));
|
|
memcpy (std_sps->dpbm.max_dec_pic_buffering_minus1,
|
|
sps->max_dec_pic_buffering_minus1, GST_H265_MAX_SUB_LAYERS
|
|
* sizeof (*std_sps->dpbm.max_dec_pic_buffering_minus1));
|
|
memcpy (std_sps->dpbm.max_num_reorder_pics,
|
|
sps->max_num_reorder_pics, GST_H265_MAX_SUB_LAYERS
|
|
* sizeof (*std_sps->dpbm.max_num_reorder_pics));
|
|
|
|
memcpy (std_sps->pal.PredictorPaletteEntries,
|
|
sps->sps_scc_extension_params.sps_palette_predictor_initializer,
|
|
STD_VIDEO_H265_PREDICTOR_PALETTE_COMPONENTS_LIST_SIZE
|
|
* sizeof (*std_sps->pal.PredictorPaletteEntries));
|
|
|
|
for (i = 0; i < sps->num_short_term_ref_pic_sets; i++) {
|
|
/* *INDENT-OFF* */
|
|
std_sps->str[i] = (StdVideoH265ShortTermRefPicSet) {
|
|
.flags = {
|
|
.inter_ref_pic_set_prediction_flag =
|
|
sps->short_term_ref_pic_set[i].inter_ref_pic_set_prediction_flag,
|
|
.delta_rps_sign = sps->short_term_ref_pic_set[i].delta_rps_sign,
|
|
},
|
|
.delta_idx_minus1 = sps->short_term_ref_pic_set[i].delta_idx_minus1,
|
|
.use_delta_flag = 0, /* FIXME: not exposed by parser and cannot deduce */
|
|
.abs_delta_rps_minus1 =
|
|
sps->short_term_ref_pic_set[i].abs_delta_rps_minus1,
|
|
.used_by_curr_pic_flag = 0, /* FIXME: not exposed by parser and cannot deduce */
|
|
.used_by_curr_pic_s0_flag =
|
|
_array_2_bitmask (sps->short_term_ref_pic_set[i].UsedByCurrPicS0,
|
|
sps->short_term_ref_pic_set[i].NumDeltaPocs),
|
|
.used_by_curr_pic_s1_flag =
|
|
_array_2_bitmask (sps->short_term_ref_pic_set[i].UsedByCurrPicS0,
|
|
sps->short_term_ref_pic_set[i].NumDeltaPocs),
|
|
/* Reserved */
|
|
/* Reserved */
|
|
/* Reserved */
|
|
.num_negative_pics = sps->short_term_ref_pic_set[i].NumNegativePics,
|
|
.num_positive_pics = sps->short_term_ref_pic_set[i].NumPositivePics,
|
|
};
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
std_sps->ltr.used_by_curr_pic_lt_sps_flag =
|
|
_array_2_bitmask (sps->used_by_curr_pic_lt_sps_flag,
|
|
sps->num_long_term_ref_pics_sps);
|
|
memcpy (std_sps->ltr.lt_ref_pic_poc_lsb_sps, sps->lt_ref_pic_poc_lsb_sps,
|
|
32 * sizeof (*std_sps->ltr.lt_ref_pic_poc_lsb_sps));
|
|
|
|
/* *INDENT-OFF* */
|
|
std_sps->sps = (StdVideoH265SequenceParameterSet) {
|
|
.flags = {
|
|
.sps_temporal_id_nesting_flag = sps->temporal_id_nesting_flag,
|
|
.separate_colour_plane_flag = sps->separate_colour_plane_flag,
|
|
.conformance_window_flag = sps->conformance_window_flag,
|
|
.sps_sub_layer_ordering_info_present_flag =
|
|
sps->sub_layer_ordering_info_present_flag,
|
|
.scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
|
|
.sps_scaling_list_data_present_flag = sps->scaling_list_enabled_flag,
|
|
.amp_enabled_flag = sps->amp_enabled_flag,
|
|
.sample_adaptive_offset_enabled_flag =
|
|
sps->sample_adaptive_offset_enabled_flag,
|
|
.pcm_enabled_flag = sps->pcm_enabled_flag,
|
|
.pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
|
|
.long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
|
|
.sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
|
|
.strong_intra_smoothing_enabled_flag =
|
|
sps->strong_intra_smoothing_enabled_flag,
|
|
.vui_parameters_present_flag = sps->vui_parameters_present_flag,
|
|
.sps_extension_present_flag = sps->sps_extension_flag,
|
|
.sps_range_extension_flag = sps->sps_range_extension_flag,
|
|
.transform_skip_rotation_enabled_flag =
|
|
sps->sps_extension_params.transform_skip_rotation_enabled_flag,
|
|
.transform_skip_context_enabled_flag =
|
|
sps->sps_extension_params.transform_skip_context_enabled_flag,
|
|
.implicit_rdpcm_enabled_flag =
|
|
sps->sps_extension_params.implicit_rdpcm_enabled_flag,
|
|
.explicit_rdpcm_enabled_flag =
|
|
sps->sps_extension_params.explicit_rdpcm_enabled_flag,
|
|
.extended_precision_processing_flag =
|
|
sps->sps_extension_params.extended_precision_processing_flag,
|
|
.intra_smoothing_disabled_flag =
|
|
sps->sps_extension_params.intra_smoothing_disabled_flag,
|
|
.high_precision_offsets_enabled_flag =
|
|
sps->sps_extension_params.high_precision_offsets_enabled_flag,
|
|
.persistent_rice_adaptation_enabled_flag =
|
|
sps->sps_extension_params.persistent_rice_adaptation_enabled_flag,
|
|
.cabac_bypass_alignment_enabled_flag =
|
|
sps->sps_extension_params.cabac_bypass_alignment_enabled_flag,
|
|
.sps_scc_extension_flag = sps->sps_scc_extension_flag,
|
|
.sps_curr_pic_ref_enabled_flag =
|
|
sps->sps_scc_extension_params.sps_curr_pic_ref_enabled_flag,
|
|
.palette_mode_enabled_flag =
|
|
sps->sps_scc_extension_params.palette_mode_enabled_flag,
|
|
.sps_palette_predictor_initializers_present_flag =
|
|
sps->sps_scc_extension_params.sps_palette_predictor_initializers_present_flag,
|
|
.intra_boundary_filtering_disabled_flag =
|
|
sps->sps_scc_extension_params.intra_boundary_filtering_disabled_flag,
|
|
},
|
|
.chroma_format_idc = sps->chroma_format_idc,
|
|
.pic_width_in_luma_samples = sps->width,
|
|
.pic_height_in_luma_samples = sps->height,
|
|
.sps_video_parameter_set_id = sps->vps_id,
|
|
.sps_max_sub_layers_minus1 = sps->max_sub_layers_minus1,
|
|
.sps_seq_parameter_set_id = sps->id,
|
|
.bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
|
|
.bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
|
|
.log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
|
|
.log2_min_luma_coding_block_size_minus3 =
|
|
sps->log2_min_luma_coding_block_size_minus3,
|
|
.log2_diff_max_min_luma_coding_block_size =
|
|
sps->log2_diff_max_min_luma_coding_block_size,
|
|
.log2_min_luma_transform_block_size_minus2 =
|
|
sps->log2_min_transform_block_size_minus2,
|
|
.log2_diff_max_min_luma_transform_block_size =
|
|
sps->log2_diff_max_min_transform_block_size,
|
|
.max_transform_hierarchy_depth_inter =
|
|
sps->max_transform_hierarchy_depth_inter,
|
|
.max_transform_hierarchy_depth_intra =
|
|
sps->max_transform_hierarchy_depth_intra,
|
|
.num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
|
|
.num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps,
|
|
.pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
|
|
.pcm_sample_bit_depth_chroma_minus1 =
|
|
sps->pcm_sample_bit_depth_chroma_minus1,
|
|
.log2_min_pcm_luma_coding_block_size_minus3 =
|
|
sps->log2_min_pcm_luma_coding_block_size_minus3,
|
|
.log2_diff_max_min_pcm_luma_coding_block_size =
|
|
sps->log2_diff_max_min_pcm_luma_coding_block_size,
|
|
/* Reserved */
|
|
/* Reserved */
|
|
.palette_max_size = sps->sps_scc_extension_params.palette_max_size,
|
|
.delta_palette_max_predictor_size =
|
|
sps->sps_scc_extension_params.delta_palette_max_predictor_size,
|
|
.motion_vector_resolution_control_idc =
|
|
sps->sps_scc_extension_params.motion_vector_resolution_control_idc,
|
|
.sps_num_palette_predictor_initializers_minus1 =
|
|
sps->sps_scc_extension_params.sps_num_palette_predictor_initializer_minus1,
|
|
.conf_win_left_offset = sps->conf_win_left_offset,
|
|
.conf_win_right_offset = sps->conf_win_right_offset,
|
|
.conf_win_top_offset = sps->conf_win_top_offset,
|
|
.conf_win_bottom_offset = sps->conf_win_bottom_offset,
|
|
.pProfileTierLevel = &std_sps->ptl,
|
|
.pDecPicBufMgr = &std_sps->dpbm,
|
|
.pScalingLists = &std_sps->scaling,
|
|
.pShortTermRefPicSet = std_sps->str,
|
|
.pLongTermRefPicsSps = &std_sps->ltr,
|
|
.pSequenceParameterSetVui = &std_sps->vui,
|
|
.pPredictorPaletteEntries = &std_sps->pal,
|
|
};
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
static void
|
|
_fill_pps (const GstH265PPS * pps, const GstH265SPS * sps, struct PPS *std_pps)
|
|
{
|
|
int i, j;
|
|
|
|
_copy_scaling_list (&pps->scaling_list, &std_pps->scaling);
|
|
|
|
/* *INDENT-OFF* */
|
|
std_pps->pps = (StdVideoH265PictureParameterSet) {
|
|
.flags = {
|
|
.dependent_slice_segments_enabled_flag =
|
|
pps->dependent_slice_segments_enabled_flag,
|
|
.output_flag_present_flag = pps->output_flag_present_flag,
|
|
.sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
|
|
.cabac_init_present_flag = pps->cabac_init_present_flag,
|
|
.constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
|
|
.transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
|
|
.cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
|
|
.pps_slice_chroma_qp_offsets_present_flag =
|
|
pps->slice_chroma_qp_offsets_present_flag,
|
|
.weighted_pred_flag = pps->weighted_pred_flag,
|
|
.weighted_bipred_flag = pps->weighted_bipred_flag,
|
|
.transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
|
|
.tiles_enabled_flag = pps->tiles_enabled_flag,
|
|
.entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
|
|
.uniform_spacing_flag = pps->uniform_spacing_flag,
|
|
.loop_filter_across_tiles_enabled_flag =
|
|
pps->loop_filter_across_tiles_enabled_flag,
|
|
.pps_loop_filter_across_slices_enabled_flag =
|
|
pps->loop_filter_across_slices_enabled_flag,
|
|
.deblocking_filter_control_present_flag =
|
|
pps->deblocking_filter_control_present_flag,
|
|
.deblocking_filter_override_enabled_flag =
|
|
pps->deblocking_filter_override_enabled_flag,
|
|
.pps_deblocking_filter_disabled_flag =
|
|
pps->deblocking_filter_disabled_flag,
|
|
.pps_scaling_list_data_present_flag = pps->scaling_list_data_present_flag,
|
|
.lists_modification_present_flag = pps->lists_modification_present_flag,
|
|
.slice_segment_header_extension_present_flag =
|
|
pps->slice_segment_header_extension_present_flag,
|
|
.pps_extension_present_flag = pps->pps_extension_flag,
|
|
.cross_component_prediction_enabled_flag =
|
|
pps->pps_extension_params.cross_component_prediction_enabled_flag,
|
|
.chroma_qp_offset_list_enabled_flag =
|
|
pps->pps_extension_params.chroma_qp_offset_list_enabled_flag,
|
|
.pps_curr_pic_ref_enabled_flag =
|
|
pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag,
|
|
.residual_adaptive_colour_transform_enabled_flag =
|
|
pps->pps_scc_extension_params.residual_adaptive_colour_transform_enabled_flag,
|
|
.pps_slice_act_qp_offsets_present_flag =
|
|
pps->pps_scc_extension_params.pps_slice_act_qp_offsets_present_flag,
|
|
.pps_palette_predictor_initializers_present_flag =
|
|
pps->pps_scc_extension_params.pps_palette_predictor_initializers_present_flag,
|
|
.monochrome_palette_flag =
|
|
pps->pps_scc_extension_params.monochrome_palette_flag,
|
|
.pps_range_extension_flag = pps->pps_range_extension_flag,
|
|
},
|
|
.pps_pic_parameter_set_id = pps->id,
|
|
.pps_seq_parameter_set_id = pps->sps_id,
|
|
.sps_video_parameter_set_id = sps->vps_id,
|
|
.num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
|
|
.num_ref_idx_l0_default_active_minus1 =
|
|
pps->num_ref_idx_l0_default_active_minus1,
|
|
.num_ref_idx_l1_default_active_minus1 =
|
|
pps->num_ref_idx_l1_default_active_minus1,
|
|
.init_qp_minus26 = pps->init_qp_minus26,
|
|
.diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
|
|
.pps_cb_qp_offset = pps->cb_qp_offset,
|
|
.pps_cr_qp_offset = pps->cr_qp_offset,
|
|
.pps_beta_offset_div2 = pps->beta_offset_div2,
|
|
.pps_tc_offset_div2 = pps->tc_offset_div2,
|
|
.log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
|
|
.log2_max_transform_skip_block_size_minus2 =
|
|
pps->pps_extension_params.log2_max_transform_skip_block_size_minus2,
|
|
.diff_cu_chroma_qp_offset_depth =
|
|
pps->pps_extension_params.diff_cu_chroma_qp_offset_depth,
|
|
.chroma_qp_offset_list_len_minus1 =
|
|
pps->pps_extension_params.chroma_qp_offset_list_len_minus1,
|
|
.log2_sao_offset_scale_luma =
|
|
pps->pps_extension_params.log2_sao_offset_scale_luma,
|
|
.log2_sao_offset_scale_chroma =
|
|
pps->pps_extension_params.log2_sao_offset_scale_chroma,
|
|
.pps_act_y_qp_offset_plus5 =
|
|
pps->pps_scc_extension_params.pps_act_y_qp_offset_plus5,
|
|
.pps_act_cb_qp_offset_plus5 =
|
|
pps->pps_scc_extension_params.pps_act_cb_qp_offset_plus5,
|
|
.pps_act_cr_qp_offset_plus3 =
|
|
pps->pps_scc_extension_params.pps_act_cr_qp_offset_plus3,
|
|
.pps_num_palette_predictor_initializers =
|
|
pps->pps_scc_extension_params.pps_num_palette_predictor_initializer,
|
|
.luma_bit_depth_entry_minus8 =
|
|
pps->pps_scc_extension_params.luma_bit_depth_entry_minus8,
|
|
.chroma_bit_depth_entry_minus8 =
|
|
pps->pps_scc_extension_params.chroma_bit_depth_entry_minus8,
|
|
.num_tile_columns_minus1 = pps->num_tile_columns_minus1,
|
|
.num_tile_rows_minus1 = pps->num_tile_rows_minus1,
|
|
.pScalingLists = &std_pps->scaling,
|
|
.pPredictorPaletteEntries = &std_pps->pal,
|
|
};
|
|
/* *INDENT-OFF* */
|
|
|
|
for (i = 0; i < (pps->pps_scc_extension_params.monochrome_palette_flag ? 1 : 3); i++) {
|
|
for (j = 0; j < pps->pps_scc_extension_params.pps_num_palette_predictor_initializer; j++) {
|
|
std_pps->pal.PredictorPaletteEntries[i][j] =
|
|
pps->pps_scc_extension_params.pps_palette_predictor_initializer[i][j];
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
|
|
std_pps->pps.column_width_minus1[i] = pps->column_width_minus1[i];
|
|
|
|
for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
|
|
std_pps->pps.row_height_minus1[i] = pps->row_height_minus1[i];
|
|
|
|
for ( i = 0; i <= pps->pps_extension_params.chroma_qp_offset_list_len_minus1 + 1; i++) {
|
|
std_pps->pps.cb_qp_offset_list[i] =
|
|
pps->pps_extension_params.cb_qp_offset_list[i];
|
|
std_pps->pps.cr_qp_offset_list[i] =
|
|
pps->pps_extension_params.cr_qp_offset_list[i];
|
|
}
|
|
}
|
|
|
|
static void
|
|
_fill_vps (const GstH265VPS * vps, struct VPS * std_vps)
|
|
{
|
|
const GstH265HRDParams *hrd = &vps->hrd_params;
|
|
|
|
if (vps->num_hrd_parameters > 1)
|
|
GST_FIXME ("H.265 parser only supports one header parameters per VPS");
|
|
|
|
if (hrd->nal_hrd_parameters_present_flag) {
|
|
_copy_sub_layers_hrd_params (hrd->sublayer_hrd_params, std_vps->nal_hdr,
|
|
GST_H265_MAX_SUB_LAYERS);
|
|
}
|
|
if (hrd->vcl_hrd_parameters_present_flag) {
|
|
_copy_sub_layers_hrd_params (hrd->sublayer_hrd_params, std_vps->vcl_hdr,
|
|
GST_H265_MAX_SUB_LAYERS);
|
|
}
|
|
|
|
/* for (i = 0; i < vps->num_hrd_parameters; i++) { */
|
|
/* *INDENT-OFF* */
|
|
std_vps->hrd = (StdVideoH265HrdParameters) {
|
|
.flags = {
|
|
.nal_hrd_parameters_present_flag = hrd->nal_hrd_parameters_present_flag,
|
|
.vcl_hrd_parameters_present_flag = hrd->vcl_hrd_parameters_present_flag,
|
|
.sub_pic_hrd_params_present_flag = hrd->sub_pic_hrd_params_present_flag,
|
|
.sub_pic_cpb_params_in_pic_timing_sei_flag =
|
|
hrd->sub_pic_cpb_params_in_pic_timing_sei_flag,
|
|
.fixed_pic_rate_general_flag =
|
|
_array_2_bitmask (hrd->fixed_pic_rate_general_flag, 7),
|
|
.fixed_pic_rate_within_cvs_flag =
|
|
_array_2_bitmask (hrd->fixed_pic_rate_within_cvs_flag, 7),
|
|
.low_delay_hrd_flag = _array_2_bitmask (hrd->low_delay_hrd_flag, 7),
|
|
},
|
|
.tick_divisor_minus2 = hrd->tick_divisor_minus2,
|
|
.du_cpb_removal_delay_increment_length_minus1 = hrd->du_cpb_removal_delay_increment_length_minus1,
|
|
.dpb_output_delay_du_length_minus1 = hrd->dpb_output_delay_du_length_minus1,
|
|
.bit_rate_scale = hrd->bit_rate_scale,
|
|
.cpb_size_scale = hrd->cpb_size_scale,
|
|
.cpb_size_du_scale = hrd->cpb_size_du_scale,
|
|
.initial_cpb_removal_delay_length_minus1 = hrd->initial_cpb_removal_delay_length_minus1,
|
|
.au_cpb_removal_delay_length_minus1 = hrd->au_cpb_removal_delay_length_minus1,
|
|
.dpb_output_delay_length_minus1 = hrd->dpb_output_delay_length_minus1,
|
|
/* Reserved: uint16_t[3] */
|
|
.pSubLayerHrdParametersNal = std_vps->nal_hdr,
|
|
.pSubLayerHrdParametersVcl = std_vps->vcl_hdr,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
_copy_profile_tier_level (&vps->profile_tier_level, &std_vps->ptl);
|
|
|
|
memcpy (std_vps->dpbm.max_latency_increase_plus1,
|
|
vps->max_latency_increase_plus1, GST_H265_MAX_SUB_LAYERS
|
|
* sizeof (*std_vps->dpbm.max_latency_increase_plus1));
|
|
memcpy (std_vps->dpbm.max_dec_pic_buffering_minus1,
|
|
vps->max_dec_pic_buffering_minus1, GST_H265_MAX_SUB_LAYERS
|
|
* sizeof (*std_vps->dpbm.max_dec_pic_buffering_minus1));
|
|
memcpy (std_vps->dpbm.max_num_reorder_pics,
|
|
vps->max_num_reorder_pics, GST_H265_MAX_SUB_LAYERS
|
|
* sizeof (*std_vps->dpbm.max_num_reorder_pics));
|
|
|
|
/* *INDENT-OFF* */
|
|
std_vps->vps = (StdVideoH265VideoParameterSet) {
|
|
.flags = {
|
|
.vps_temporal_id_nesting_flag = vps->temporal_id_nesting_flag,
|
|
.vps_sub_layer_ordering_info_present_flag =
|
|
vps->sub_layer_ordering_info_present_flag,
|
|
.vps_timing_info_present_flag = vps->timing_info_present_flag,
|
|
.vps_poc_proportional_to_timing_flag =
|
|
vps->poc_proportional_to_timing_flag,
|
|
},
|
|
.vps_video_parameter_set_id = vps->id,
|
|
.vps_max_sub_layers_minus1 = vps->max_sub_layers_minus1,
|
|
/* Reserved */
|
|
/* Reserved */
|
|
.vps_num_units_in_tick = vps->num_units_in_tick,
|
|
.vps_time_scale = vps->time_scale,
|
|
.vps_num_ticks_poc_diff_one_minus1 = vps->num_ticks_poc_diff_one_minus1,
|
|
/* Reserved */
|
|
.pDecPicBufMgr = &std_vps->dpbm,
|
|
.pHrdParameters = &std_vps->hrd,
|
|
.pProfileTierLevel = &std_vps->ptl,
|
|
};
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
static GstFlowReturn
|
|
_update_parameters (GstVulkanH265Decoder * self, const GstH265PPS * pps)
|
|
{
|
|
GstH265SPS *sps = pps->sps;
|
|
GstH265VPS *vps = sps->vps;
|
|
struct SPS std_sps;
|
|
struct PPS std_pps;
|
|
struct VPS std_vps;
|
|
VkVideoDecodeH265SessionParametersAddInfoKHR params = {
|
|
.sType =
|
|
VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR,
|
|
.stdSPSCount = 1,
|
|
.pStdSPSs = &std_sps.sps,
|
|
.stdPPSCount = 1,
|
|
.pStdPPSs = &std_pps.pps,
|
|
.stdVPSCount = 1,
|
|
.pStdVPSs = &std_vps.vps,
|
|
};
|
|
/* *INDENT-OFF* */
|
|
GstVulkanDecoderParameters dec_params = {
|
|
.h265 = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR,
|
|
/* .pNext = */
|
|
.maxStdSPSCount = params.stdSPSCount,
|
|
.maxStdPPSCount = params.stdPPSCount,
|
|
.pParametersAddInfo = ¶ms,
|
|
}
|
|
};
|
|
/* *INDENT-ON* */
|
|
GError *error = NULL;
|
|
|
|
_fill_sps (sps, &std_sps);
|
|
_fill_pps (pps, sps, &std_pps);
|
|
_fill_vps (vps, &std_vps);
|
|
|
|
if (!gst_vulkan_decoder_update_video_session_parameters (self->decoder,
|
|
&dec_params, &error)) {
|
|
if (error) {
|
|
GST_ERROR_OBJECT (self, "Couldn't set codec parameters: %s",
|
|
error->message);
|
|
g_clear_error (&error);
|
|
}
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static gint32
|
|
_find_next_slot_idx (GArray * dpb)
|
|
{
|
|
gint32 i;
|
|
guint len;
|
|
GstH265Picture *arr[16] = { NULL, };
|
|
|
|
g_assert (dpb->len < 16);
|
|
|
|
len = dpb->len;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
GstH265Picture *pic = g_array_index (dpb, GstH265Picture *, i);
|
|
GstVulkanH265Picture *h265_pic;
|
|
|
|
if (!pic->ref)
|
|
continue;
|
|
|
|
h265_pic = gst_h265_picture_get_user_data (pic);
|
|
arr[h265_pic->slot_idx] = pic;
|
|
}
|
|
|
|
/* let's return the smallest available / not ref index */
|
|
for (i = 0; i < len; i++) {
|
|
if (!arr[i])
|
|
return i;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static void
|
|
_fill_ref_slot (GstVulkanH265Decoder * self, GstH265Picture * picture,
|
|
VkVideoReferenceSlotInfoKHR * slot, VkVideoPictureResourceInfoKHR * res,
|
|
VkVideoDecodeH265DpbSlotInfoKHR * vkh265_slot,
|
|
StdVideoDecodeH265ReferenceInfo * stdh265_ref,
|
|
GstVulkanDecoderPicture ** ref)
|
|
{
|
|
GstVulkanH265Picture *pic = gst_h265_picture_get_user_data (picture);
|
|
|
|
/* *INDENT-OFF* */
|
|
*stdh265_ref = (StdVideoDecodeH265ReferenceInfo) {
|
|
.flags = {
|
|
.used_for_long_term_reference = picture->ref && picture->long_term,
|
|
.unused_for_reference = 0,
|
|
},
|
|
.PicOrderCntVal = picture->pic_order_cnt,
|
|
};
|
|
|
|
*vkh265_slot = (VkVideoDecodeH265DpbSlotInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR,
|
|
.pStdReferenceInfo = stdh265_ref,
|
|
};
|
|
|
|
*res = (VkVideoPictureResourceInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
|
.codedOffset = { self->x, self->y },
|
|
.codedExtent = { self->width, self->height },
|
|
.baseArrayLayer = self->decoder->layered_dpb ? pic->slot_idx : 0,
|
|
.imageViewBinding = pic->base.img_view_ref->view,
|
|
};
|
|
|
|
*slot = (VkVideoReferenceSlotInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR,
|
|
.pNext = vkh265_slot,
|
|
.slotIndex = pic->slot_idx,
|
|
.pPictureResource = res,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
if (ref)
|
|
*ref = &pic->base;
|
|
|
|
|
|
GST_TRACE_OBJECT (self, "0x%lx slotIndex: %d", res->imageViewBinding,
|
|
slot->slotIndex);
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_vulkan_h265_decoder_start_picture (GstH265Decoder * decoder,
|
|
GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
GstH265PPS *pps = slice->header.pps;
|
|
GstFlowReturn ret;
|
|
GstVulkanH265Picture *pic;
|
|
GArray *refs;
|
|
guint i, j, num_refs;
|
|
|
|
GST_TRACE_OBJECT (self, "Start picture");
|
|
|
|
if (self->need_params_update) {
|
|
ret = _update_parameters (self, pps);
|
|
if (ret != GST_FLOW_OK)
|
|
return ret;
|
|
self->need_params_update = FALSE;
|
|
}
|
|
|
|
refs = gst_h265_dpb_get_pictures_all (dpb);
|
|
|
|
pic = gst_h265_picture_get_user_data (picture);
|
|
g_assert (pic);
|
|
|
|
/* *INDENT-OFF* */
|
|
pic->std_h265pic = (StdVideoDecodeH265PictureInfo) {
|
|
.flags = {
|
|
.IrapPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
|
|
.IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
|
|
.IsReference = picture->ref,
|
|
.short_term_ref_pic_set_sps_flag =
|
|
slice->header.short_term_ref_pic_set_sps_flag,
|
|
},
|
|
.sps_video_parameter_set_id = pps->sps->vps_id,
|
|
.pps_seq_parameter_set_id = pps->sps_id,
|
|
.pps_pic_parameter_set_id = pps->id,
|
|
.NumDeltaPocsOfRefRpsIdx =
|
|
slice->header.short_term_ref_pic_sets.NumDeltaPocsOfRefRpsIdx,
|
|
.PicOrderCntVal = picture->pic_order_cnt,
|
|
.NumBitsForSTRefPicSetInSlice =
|
|
!slice->header.short_term_ref_pic_set_sps_flag ?
|
|
slice->header.short_term_ref_pic_set_size : 0,
|
|
};
|
|
|
|
pic->vk_h265pic = (VkVideoDecodeH265PictureInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR,
|
|
.pStdPictureInfo = &pic->std_h265pic,
|
|
.sliceSegmentCount = 0,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
pic->slot_idx = _find_next_slot_idx (refs);
|
|
|
|
/* fill main slot */
|
|
_fill_ref_slot (self, picture, &pic->base.slot, &pic->base.pic_res,
|
|
&pic->vk_slot, &pic->std_ref, NULL);
|
|
|
|
j = 0;
|
|
|
|
for (i = 0; i < refs->len; i++) {
|
|
GstH265Picture *ref_pic = g_array_index (refs, GstH265Picture *, i);
|
|
if (!ref_pic->ref)
|
|
continue;
|
|
_fill_ref_slot (self, ref_pic, &pic->base.slots[j], &pic->base.pics_res[j],
|
|
&pic->vk_slots[j], &pic->std_refs[j], &pic->base.refs[j]);
|
|
j++;
|
|
}
|
|
|
|
num_refs = j;
|
|
|
|
memset (pic->std_h265pic.RefPicSetStCurrBefore, 0xff, 8);
|
|
memset (pic->std_h265pic.RefPicSetStCurrAfter, 0xff, 8);
|
|
memset (pic->std_h265pic.RefPicSetLtCurr, 0xff, 8);
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrBefore); i++) {
|
|
for (j = 0; j < refs->len; j++) {
|
|
GstH265Picture *ref_pic = g_array_index (refs, GstH265Picture *, j);
|
|
if (ref_pic == decoder->RefPicSetStCurrBefore[i]) {
|
|
GstVulkanH265Picture *h265_ref_pic =
|
|
gst_h265_picture_get_user_data (ref_pic);
|
|
pic->std_h265pic.RefPicSetStCurrBefore[i] = h265_ref_pic->slot_idx;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrAfter); i++) {
|
|
for (j = 0; j < refs->len; j++) {
|
|
GstH265Picture *ref_pic = g_array_index (refs, GstH265Picture *, j);
|
|
if (ref_pic == decoder->RefPicSetStCurrAfter[i]) {
|
|
GstVulkanH265Picture *h265_ref_pic =
|
|
gst_h265_picture_get_user_data (ref_pic);
|
|
pic->std_h265pic.RefPicSetStCurrAfter[i] = h265_ref_pic->slot_idx;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetLtCurr); i++) {
|
|
for (j = 0; j < refs->len; j++) {
|
|
GstH265Picture *ref_pic = g_array_index (refs, GstH265Picture *, j);
|
|
if (ref_pic == decoder->RefPicSetLtCurr[i]) {
|
|
GstVulkanH265Picture *h265_ref_pic =
|
|
gst_h265_picture_get_user_data (ref_pic);
|
|
pic->std_h265pic.RefPicSetLtCurr[i] = h265_ref_pic->slot_idx;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_array_unref (refs);
|
|
|
|
|
|
/* *INDENT-OFF* */
|
|
pic->base.decode_info = (VkVideoDecodeInfoKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR,
|
|
.pNext = &pic->vk_h265pic,
|
|
.flags = 0x0,
|
|
.pSetupReferenceSlot = &pic->base.slot,
|
|
.referenceSlotCount = num_refs,
|
|
.pReferenceSlots = (const VkVideoReferenceSlotInfoKHR *) &pic->base.slots,
|
|
.dstPictureResource = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
|
.codedOffset = { self->x, self->y },
|
|
.codedExtent = { self->coded_width, self->coded_height },
|
|
.baseArrayLayer = 0,
|
|
.imageViewBinding = pic->base.img_view_out->view,
|
|
},
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
/* only wait if there's a buffer processed */
|
|
if (GST_CODEC_PICTURE_FRAME_NUMBER (picture) > 0) {
|
|
if (!gst_vulkan_decoder_wait (self->decoder)) {
|
|
GST_ERROR_OBJECT (self, "Error at waiting for decoding operation to end");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_vulkan_h265_decoder_decode_slice (GstH265Decoder * decoder,
|
|
GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
|
|
GArray * ref_pic_list1)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
GstVulkanH265Picture *pic;
|
|
|
|
GST_TRACE_OBJECT (self, "Decode slice");
|
|
|
|
pic = gst_h265_picture_get_user_data (picture);
|
|
g_assert (pic);
|
|
|
|
if (!gst_vulkan_decoder_append_slice (self->decoder, &pic->base,
|
|
slice->nalu.data + slice->nalu.offset, slice->nalu.size, TRUE))
|
|
return GST_FLOW_ERROR;
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_vulkan_h265_decoder_end_picture (GstH265Decoder * decoder,
|
|
GstH265Picture * picture)
|
|
{
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
GstVulkanH265Picture *pic;
|
|
GError *error = NULL;
|
|
|
|
GST_TRACE_OBJECT (self, "End picture");
|
|
|
|
pic = gst_h265_picture_get_user_data (picture);
|
|
g_assert (pic);
|
|
|
|
if (pic->base.slice_offs->len == 0)
|
|
return GST_FLOW_OK;
|
|
|
|
pic->vk_h265pic.sliceSegmentCount = pic->base.slice_offs->len - 1;
|
|
pic->vk_h265pic.pSliceSegmentOffsets =
|
|
(const guint32 *) pic->base.slice_offs->data;
|
|
|
|
GST_LOG_OBJECT (self, "Decoding frame, %d bytes %d slices",
|
|
pic->vk_h265pic.pSliceSegmentOffsets[pic->vk_h265pic.sliceSegmentCount],
|
|
pic->vk_h265pic.sliceSegmentCount);
|
|
|
|
if (!gst_vulkan_decoder_decode (self->decoder, &pic->base, &error)) {
|
|
GST_ERROR_OBJECT (self, "Couldn't decode frame: %s",
|
|
error ? error->message : "");
|
|
g_clear_error (&error);
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_vulkan_h265_decoder_output_picture (GstH265Decoder * decoder,
|
|
GstVideoCodecFrame * frame, GstH265Picture * picture)
|
|
{
|
|
GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
|
|
GstVulkanH265Decoder *self = GST_VULKAN_H265_DECODER (decoder);
|
|
|
|
GST_TRACE_OBJECT (self, "Output picture");
|
|
|
|
GST_LOG_OBJECT (self,
|
|
"Outputting picture %p (poc %d)", picture, picture->pic_order_cnt);
|
|
|
|
if (GST_CODEC_PICTURE (picture)->discont_state) {
|
|
self->need_negotiation = TRUE;
|
|
if (!gst_video_decoder_negotiate (vdec)) {
|
|
gst_h265_picture_unref (picture);
|
|
GST_ERROR_OBJECT (self, "Could not re-negotiate with updated state");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
}
|
|
|
|
gst_h265_picture_unref (picture);
|
|
|
|
reset_pipeline_stage_mask (frame->output_buffer);
|
|
|
|
return gst_video_decoder_finish_frame (vdec, frame);
|
|
}
|
|
|
|
static void
|
|
gst_vulkan_h265_decoder_init (GstVulkanH265Decoder * self)
|
|
{
|
|
gst_vulkan_buffer_memory_init_once ();
|
|
}
|
|
|
|
static void
|
|
gst_vulkan_h265_decoder_class_init (GstVulkanH265DecoderClass * klass)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
|
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
|
|
GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (klass);
|
|
|
|
gst_element_class_set_metadata (element_class, "Vulkan H.265 decoder",
|
|
"Codec/Decoder/Video/Hardware", "A H.265 video decoder based on Vulkan",
|
|
"Víctor Jáquez <vjaquez@igalia.com>");
|
|
|
|
gst_element_class_add_static_pad_template (element_class,
|
|
&gst_vulkan_h265dec_sink_template);
|
|
|
|
gst_element_class_add_static_pad_template (element_class,
|
|
&gst_vulkan_h265dec_src_template);
|
|
|
|
element_class->set_context =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_set_context);
|
|
|
|
decoder_class->src_query =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_src_query);
|
|
decoder_class->sink_query =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_sink_query);
|
|
decoder_class->open = GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_open);
|
|
decoder_class->close = GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_close);
|
|
decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_stop);
|
|
decoder_class->negotiate =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_negotiate);
|
|
decoder_class->decide_allocation =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_decide_allocation);
|
|
|
|
h265decoder_class->new_sequence =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_new_sequence);
|
|
h265decoder_class->new_picture =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_new_picture);
|
|
h265decoder_class->start_picture =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_start_picture);
|
|
h265decoder_class->decode_slice =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_decode_slice);
|
|
h265decoder_class->end_picture =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_end_picture);
|
|
h265decoder_class->output_picture =
|
|
GST_DEBUG_FUNCPTR (gst_vulkan_h265_decoder_output_picture);
|
|
}
|