d3d12: Support writing H264 temporal scalability prefix slice NAL on demand
Reviewed-By: Pohsiang (John) Hsu <pohhsu@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31268>
This commit is contained in:
@@ -297,6 +297,9 @@ d3d12_video_encoder_destroy(struct pipe_video_codec *codec)
|
||||
d3d12_video_encoder_sync_completion(codec, pD3D12Enc->m_spFence.Get(), curBatchFence, OS_TIMEOUT_INFINITE);
|
||||
}
|
||||
|
||||
if (pD3D12Enc->m_nalPrefixTmpBuffer)
|
||||
pD3D12Enc->m_screen->resource_destroy(pD3D12Enc->m_screen, pD3D12Enc->m_nalPrefixTmpBuffer);
|
||||
|
||||
// Call d3d12_video_encoder dtor to make ComPtr and other member's destructors work
|
||||
delete pD3D12Enc;
|
||||
}
|
||||
@@ -1611,6 +1614,32 @@ d3d12_video_encoder_create_command_objects(struct d3d12_video_encoder *pD3D12Enc
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
d3d12_video_encoder_reallocate_prefix_nal_buffer(struct d3d12_video_encoder *pD3D12Enc,
|
||||
pipe_resource** out_buffer,
|
||||
uint32_t byte_size)
|
||||
{
|
||||
if (*out_buffer != NULL)
|
||||
{
|
||||
debug_printf("[d3d12_video_encoder_reallocate_prefix_nal_buffer] Destroying existing buffer at address: 0x%p byte size: %d\n", *out_buffer, (*out_buffer)->width0);
|
||||
pD3D12Enc->m_screen->resource_destroy(pD3D12Enc->m_screen, *out_buffer);
|
||||
*out_buffer = NULL;
|
||||
}
|
||||
|
||||
struct pipe_resource templ = { };
|
||||
memset(&templ, 0, sizeof(templ));
|
||||
templ.target = PIPE_BUFFER;
|
||||
templ.usage = PIPE_USAGE_DEFAULT;
|
||||
templ.format = PIPE_FORMAT_R8_UINT;
|
||||
templ.width0 = byte_size;
|
||||
templ.height0 = 1;
|
||||
templ.depth0 = 1;
|
||||
templ.array_size = 1;
|
||||
*out_buffer = pD3D12Enc->m_screen->resource_create(pD3D12Enc->m_screen, &templ);
|
||||
assert(*out_buffer);
|
||||
debug_printf("[d3d12_video_encoder_reallocate_prefix_nal_buffer] Created new buffer at address: 0x%p byte size: %d\n", *out_buffer, (*out_buffer)->width0);
|
||||
}
|
||||
|
||||
struct pipe_video_codec *
|
||||
d3d12_video_encoder_create_encoder(struct pipe_context *context, const struct pipe_video_codec *codec)
|
||||
{
|
||||
@@ -2014,6 +2043,9 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
|
||||
assert(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize == pD3D12Enc->m_BitstreamHeadersBuffer.size());
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersBytePadding = 0;
|
||||
|
||||
// Save the pipe destination buffer the headers need to be written to in get_feedback if post encode headers needed or H264 SVC NAL prefixes, etc
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination = &pOutputBitstreamBuffer->base.b;
|
||||
|
||||
// Only upload headers now and leave prefix offset space gap in compressed bitstream if the codec builds headers before execution.
|
||||
if (!pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].postEncodeHeadersNeeded)
|
||||
{
|
||||
@@ -2075,9 +2107,6 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
|
||||
// Headers are written after execution, have EncodeFrame write into a staging buffer
|
||||
// and then get_feedback will pack the finalized bitstream and copy into comp_bit_destination
|
||||
pOutputBufferD3D12Res = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spStagingBitstream.Get();
|
||||
|
||||
// Save the pipe destination buffer the headers need to be written to in get_feedback
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination = &pOutputBitstreamBuffer->base.b;
|
||||
}
|
||||
|
||||
memset(&pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_FenceData,
|
||||
@@ -2462,6 +2491,133 @@ d3d12_video_encoder_get_feedback(struct pipe_video_codec *codec,
|
||||
}
|
||||
else
|
||||
{
|
||||
#if VIDEO_CODEC_H264ENC
|
||||
// Add H264 temporal layers slice nal prefixes if necessary
|
||||
if ((D3D12_VIDEO_ENCODER_CODEC_H264 == pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderCodecDesc)
|
||||
&& (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_svcprefix_slice_header)
|
||||
&& (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264.num_temporal_layers > 1))
|
||||
{
|
||||
if (!pD3D12Enc->m_nalPrefixTmpBuffer)
|
||||
d3d12_video_encoder_reallocate_prefix_nal_buffer(pD3D12Enc,
|
||||
&pD3D12Enc->m_nalPrefixTmpBuffer,
|
||||
D3D12_DEFAULT_COMPBIT_STAGING_SIZE);
|
||||
assert (pD3D12Enc->m_nalPrefixTmpBuffer);
|
||||
|
||||
//
|
||||
// Copy slices from driver comp_bit_destination into m_nalPrefixTmpBuffer with collated slices NAL prefixes
|
||||
//
|
||||
// Skip SPS, PPS, etc first preEncodeGeneratedHeadersByteSize bytes in src_driver_buffer_read_bytes
|
||||
uint32_t src_driver_buffer_read_bytes = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize;
|
||||
uint32_t dst_tmp_buffer_written_bytes = 0;
|
||||
uint32_t num_slices = pSubregionsMetadata.size();
|
||||
std::vector<std::vector<uint8_t> > prefix_nal_bufs;
|
||||
prefix_nal_bufs.resize(num_slices);
|
||||
size_t written_prefix_nal_bytes = 0;
|
||||
for (uint32_t cur_slice_idx = 0; cur_slice_idx < num_slices; cur_slice_idx++)
|
||||
{
|
||||
// At the end of the loop we're inserting at pSubregionsMetadata.insert(std::next(pSubregionsMetadata.begin()
|
||||
// so we have to 2x the loop current index to index the current slice, skipping the prefix NALs of the previously processed slices
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA cur_subregion_metadata = pSubregionsMetadata[2 * cur_slice_idx];
|
||||
|
||||
d3d12_video_encoder_build_slice_svc_prefix_nalu_h264(pD3D12Enc,
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot],
|
||||
prefix_nal_bufs[cur_slice_idx],
|
||||
prefix_nal_bufs[cur_slice_idx].begin(),
|
||||
written_prefix_nal_bytes);
|
||||
|
||||
// Upload nal prefix to m_nalPrefixTmpBuffer
|
||||
pD3D12Enc->base.context->buffer_subdata(pD3D12Enc->base.context, // context
|
||||
pD3D12Enc->m_nalPrefixTmpBuffer, // dst buffer
|
||||
PIPE_MAP_WRITE, // dst usage PIPE_MAP_x
|
||||
dst_tmp_buffer_written_bytes, // dst offset
|
||||
written_prefix_nal_bytes, // src size
|
||||
prefix_nal_bufs[cur_slice_idx].data()); // src void* buffer
|
||||
dst_tmp_buffer_written_bytes += written_prefix_nal_bytes;
|
||||
|
||||
// Copy slice (padded as-is) cur_subregion_metadata.bSize at src_driver_buffer_read_bytes into m_nalPrefixTmpBuffer AFTER the prefix nal (written_prefix_nal_bytes) to m_nalPrefixTmpBuffer
|
||||
struct pipe_box src_box = {};
|
||||
u_box_3d(src_driver_buffer_read_bytes, // x
|
||||
0, // y
|
||||
0, // z
|
||||
static_cast<int>(cur_subregion_metadata.bSize), // width
|
||||
1, // height
|
||||
1, // depth
|
||||
&src_box
|
||||
);
|
||||
|
||||
pD3D12Enc->base.context->resource_copy_region(pD3D12Enc->base.context, // ctx
|
||||
pD3D12Enc->m_nalPrefixTmpBuffer, // dst
|
||||
0, // dst_level
|
||||
dst_tmp_buffer_written_bytes, // dstX - Skip the other headers in the final bitstream (e.g SPS, PPS, etc)
|
||||
0, // dstY
|
||||
0, // dstZ
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination, // src
|
||||
0, // src level
|
||||
&src_box);
|
||||
src_driver_buffer_read_bytes += cur_subregion_metadata.bSize;
|
||||
dst_tmp_buffer_written_bytes += cur_subregion_metadata.bSize;
|
||||
|
||||
// Insert prefix NAL before current slice in cur_subregion_metadata so it's treated as just another NAL below for reporting metadata
|
||||
pSubregionsMetadata.insert(std::next(pSubregionsMetadata.begin(), 2 * cur_slice_idx), { /* bSize */ written_prefix_nal_bytes, /* bStartOffset */ 0, /* bHeaderSize */ 0 });
|
||||
}
|
||||
|
||||
//
|
||||
// Copy from m_nalPrefixTmpBuffer with prefixes and slices back into comp_bit_destination
|
||||
//
|
||||
|
||||
// Make sure we have enough space in destination buffer
|
||||
if (dst_tmp_buffer_written_bytes >
|
||||
(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize + pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination->width0))
|
||||
{
|
||||
opt_metadata.encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
|
||||
debug_printf("[d3d12_video_encoder] Insufficient compressed buffer size passed from frontend while building the H264 SVC NAL prefixes.\n");
|
||||
assert(false);
|
||||
if(pMetadata)
|
||||
*pMetadata = opt_metadata;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
struct pipe_box src_box = {};
|
||||
u_box_3d(0, // x
|
||||
0, // y
|
||||
0, // z
|
||||
static_cast<int>(dst_tmp_buffer_written_bytes), // width
|
||||
1, // height
|
||||
1, // depth
|
||||
&src_box
|
||||
);
|
||||
|
||||
pD3D12Enc->base.context->resource_copy_region(pD3D12Enc->base.context, // ctx
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination, // dst
|
||||
0, // dst_level
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize,// dstX - Skip the other headers in the final bitstream (e.g SPS, PPS, etc)
|
||||
0, // dstY
|
||||
0, // dstZ
|
||||
pD3D12Enc->m_nalPrefixTmpBuffer, // src
|
||||
0, // src level
|
||||
&src_box);
|
||||
|
||||
//
|
||||
// Flush copies in batch and wait on this CPU thread for GPU work completion
|
||||
//
|
||||
{
|
||||
struct pipe_fence_handle *pUploadGPUCompletionFence = NULL;
|
||||
pD3D12Enc->base.context->flush(pD3D12Enc->base.context,
|
||||
&pUploadGPUCompletionFence,
|
||||
PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
|
||||
assert(pUploadGPUCompletionFence);
|
||||
pD3D12Enc->m_pD3D12Screen->base.fence_finish(&pD3D12Enc->m_pD3D12Screen->base,
|
||||
NULL,
|
||||
pUploadGPUCompletionFence,
|
||||
OS_TIMEOUT_INFINITE);
|
||||
pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base,
|
||||
&pUploadGPUCompletionFence,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
#endif // VIDEO_CODEC_H264ENC
|
||||
|
||||
*output_buffer_size = 0;
|
||||
for (uint32_t i = 0; i < pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes.size() ; i++) {
|
||||
unpadded_frame_size += pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes[i];
|
||||
|
||||
@@ -137,6 +137,7 @@ enum d3d12_video_encoder_config_dirty_flags
|
||||
d3d12_video_encoder_config_dirty_flag_picture_header = 0x2000,
|
||||
d3d12_video_encoder_config_dirty_flag_aud_header = 0x4000,
|
||||
d3d12_video_encoder_config_dirty_flag_sei_header = 0x8000,
|
||||
d3d12_video_encoder_config_dirty_flag_svcprefix_slice_header = 0x10000,
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(d3d12_video_encoder_config_dirty_flags);
|
||||
|
||||
@@ -287,6 +288,8 @@ struct D3D12EncodeConfiguration
|
||||
struct pipe_h265_enc_seq_param m_encoderCodecSpecificSequenceStateDescH265;
|
||||
struct pipe_h265_enc_vid_param m_encoderCodecSpecificVideoStateDescH265;
|
||||
struct pipe_h265_enc_pic_param m_encoderCodecSpecificPictureStateDescH265;
|
||||
|
||||
bool m_bUsedAsReference; // Set if frame will be used as reference frame
|
||||
};
|
||||
|
||||
struct EncodedBitstreamResolvedMetadata
|
||||
@@ -408,6 +411,7 @@ struct d3d12_video_encoder
|
||||
std::shared_ptr<d3d12_video_dpb_storage_manager_interface> m_upDPBStorageManager;
|
||||
std::unique_ptr<d3d12_video_bitstream_builder_interface> m_upBitstreamBuilder;
|
||||
|
||||
pipe_resource* m_nalPrefixTmpBuffer = NULL;
|
||||
std::vector<uint8_t> m_BitstreamHeadersBuffer;
|
||||
std::vector<uint8_t> m_StagingHeadersBuffer;
|
||||
std::vector<EncodedBitstreamResolvedMetadata> m_spEncodedFrameMetadata;
|
||||
|
||||
@@ -1218,7 +1218,8 @@ d3d12_video_encoder_update_current_frame_pic_params_info_av1(struct d3d12_video_
|
||||
struct pipe_av1_enc_picture_desc *pAV1Pic = (struct pipe_av1_enc_picture_desc *) picture;
|
||||
|
||||
// Output param bUsedAsReference
|
||||
bUsedAsReference = (pAV1Pic->refresh_frame_flags != 0);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference = (pAV1Pic->refresh_frame_flags != 0);
|
||||
bUsedAsReference = pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference;
|
||||
|
||||
// D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS Flags;
|
||||
picParams.pAV1PicData->Flags = D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_NONE;
|
||||
|
||||
@@ -356,7 +356,8 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
|
||||
static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
|
||||
assert(pH264BitstreamBuilder != nullptr);
|
||||
|
||||
bUsedAsReference = !h264Pic->not_referenced;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference = !h264Pic->not_referenced;
|
||||
bUsedAsReference = pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference;
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps.SupportFlags &
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE_SUPPORT)
|
||||
@@ -391,6 +392,13 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
|
||||
picParams.pH264PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit.data();
|
||||
picParams.pH264PicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit.size();
|
||||
}
|
||||
|
||||
// Save state snapshot from record time to resolve headers at get_feedback time
|
||||
uint64_t current_metadata_slot = (pD3D12Enc->m_fenceValue % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT);
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeCapabilities =
|
||||
pD3D12Enc->m_currentEncodeCapabilities;
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig =
|
||||
pD3D12Enc->m_currentEncodeConfig;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -933,6 +941,8 @@ d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_
|
||||
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_aud_header;
|
||||
else if (header->type == NAL_TYPE_SEI)
|
||||
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sei_header;
|
||||
else if (header->type == NAL_TYPE_PREFIX)
|
||||
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_svcprefix_slice_header;
|
||||
}
|
||||
|
||||
// Set input format
|
||||
@@ -1262,3 +1272,36 @@ d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder *pD3D12E
|
||||
static_cast<uint64_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size()));
|
||||
return pD3D12Enc->m_BitstreamHeadersBuffer.size();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
d3d12_video_encoder_build_slice_svc_prefix_nalu_h264(struct d3d12_video_encoder * pD3D12Enc,
|
||||
EncodedBitstreamResolvedMetadata& associatedMetadata,
|
||||
std::vector<uint8_t> & headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenSVCPrefixNalBytes)
|
||||
{
|
||||
d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
|
||||
static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
|
||||
assert(pH264BitstreamBuilder);
|
||||
|
||||
H264_SLICE_PREFIX_SVC nal_svc_prefix = {};
|
||||
memset(&nal_svc_prefix, 0, sizeof(nal_svc_prefix));
|
||||
nal_svc_prefix.idr_flag = (associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME) ? 1 : 0;
|
||||
nal_svc_prefix.no_inter_layer_pred_flag = 1;
|
||||
nal_svc_prefix.output_flag = 1;
|
||||
nal_svc_prefix.discardable_flag = 1;
|
||||
nal_svc_prefix.temporal_id = associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.TemporalLayerIndex;
|
||||
nal_svc_prefix.priority_id = nal_svc_prefix.temporal_id;
|
||||
nal_svc_prefix.nal_ref_idc = associatedMetadata.m_associatedEncodeConfig.m_bUsedAsReference ? NAL_REFIDC_REF : NAL_REFIDC_NONREF;
|
||||
pH264BitstreamBuilder->write_slice_svc_prefix(nal_svc_prefix,
|
||||
headerBitstream,
|
||||
placingPositionStart,
|
||||
writtenSVCPrefixNalBytes);
|
||||
|
||||
// Shrink buffer to fit the headers
|
||||
if (headerBitstream.size() > (writtenSVCPrefixNalBytes)) {
|
||||
headerBitstream.resize(writtenSVCPrefixNalBytes);
|
||||
}
|
||||
|
||||
return headerBitstream.size();
|
||||
}
|
||||
@@ -64,4 +64,11 @@ d3d12_video_encoder_compare_slice_config_h264_hevc(
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig);
|
||||
|
||||
uint32_t
|
||||
d3d12_video_encoder_build_slice_svc_prefix_nalu_h264(struct d3d12_video_encoder * pD3D12Enc,
|
||||
EncodedBitstreamResolvedMetadata& associatedMetadata,
|
||||
std::vector<uint8_t> & headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenSVCPrefixNalBytes);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -354,7 +354,8 @@ d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video
|
||||
static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
|
||||
assert(pHEVCBitstreamBuilder != nullptr);
|
||||
|
||||
bUsedAsReference = !hevcPic->not_referenced;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference = !hevcPic->not_referenced;
|
||||
bUsedAsReference = pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference;
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags &
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE_SUPPORT)
|
||||
@@ -492,6 +493,13 @@ d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video
|
||||
picParams.pHEVCPicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.data();
|
||||
picParams.pHEVCPicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.size();
|
||||
}
|
||||
|
||||
// Save state snapshot from record time to resolve headers at get_feedback time
|
||||
uint64_t current_metadata_slot = (pD3D12Enc->m_fenceValue % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT);
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeCapabilities =
|
||||
pD3D12Enc->m_currentEncodeCapabilities;
|
||||
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig =
|
||||
pD3D12Enc->m_currentEncodeConfig;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@@ -209,6 +209,15 @@ d3d12_video_bitstream_builder_h264::write_sei_messages(const std::vector<H264_SE
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_h264::write_slice_svc_prefix(const H264_SLICE_PREFIX_SVC & nal_svc_prefix,
|
||||
std::vector<uint8_t> & headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenBytes)
|
||||
{
|
||||
m_h264Encoder.write_slice_svc_prefix(nal_svc_prefix, headerBitstream, placingPositionStart, writtenBytes);
|
||||
}
|
||||
|
||||
H264_PPS
|
||||
d3d12_video_bitstream_builder_h264::build_pps(const enum pipe_video_profile & profile,
|
||||
const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 & codecConfig,
|
||||
|
||||
@@ -72,6 +72,10 @@ class d3d12_video_bitstream_builder_h264 : public d3d12_video_bitstream_builder_
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenBytes);
|
||||
|
||||
void write_slice_svc_prefix(const H264_SLICE_PREFIX_SVC & nal_svc_prefix,
|
||||
std::vector<uint8_t> & headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenBytes);
|
||||
|
||||
void print_pps(const H264_PPS &pps);
|
||||
void print_sps(const H264_SPS &sps);
|
||||
|
||||
@@ -268,7 +268,8 @@ uint32_t
|
||||
d3d12_video_nalu_writer_h264::wrap_rbsp_into_nalu(d3d12_video_encoder_bitstream *pNALU,
|
||||
d3d12_video_encoder_bitstream *pRBSP,
|
||||
uint32_t iNaluIdc,
|
||||
uint32_t iNaluType)
|
||||
uint32_t iNaluType,
|
||||
const H264_SLICE_PREFIX_SVC* pSvcExtendedHeader)
|
||||
{
|
||||
bool isAligned = pRBSP->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
|
||||
assert(isAligned);
|
||||
@@ -285,6 +286,24 @@ d3d12_video_nalu_writer_h264::wrap_rbsp_into_nalu(d3d12_video_encoder_bitstream
|
||||
pNALU->put_bits(1, 0);
|
||||
pNALU->put_bits(2, iNaluIdc);
|
||||
pNALU->put_bits(5, iNaluType);
|
||||
|
||||
if (iNaluType == NAL_TYPE_PREFIX)
|
||||
{
|
||||
assert(pSvcExtendedHeader);
|
||||
pNALU->put_bits(1, 1); // svc_extension_flag u(1)
|
||||
// nal_unit_header_svc_extension( )
|
||||
pNALU->put_bits(1, pSvcExtendedHeader->idr_flag);
|
||||
pNALU->put_bits(6, pSvcExtendedHeader->priority_id);
|
||||
pNALU->put_bits(1, pSvcExtendedHeader->no_inter_layer_pred_flag);
|
||||
pNALU->put_bits(3, pSvcExtendedHeader->dependency_id);
|
||||
pNALU->put_bits(4, pSvcExtendedHeader->quality_id);
|
||||
pNALU->put_bits(3, pSvcExtendedHeader->temporal_id);
|
||||
pNALU->put_bits(1, pSvcExtendedHeader->use_ref_base_pic_flag);
|
||||
pNALU->put_bits(1, pSvcExtendedHeader->discardable_flag);
|
||||
pNALU->put_bits(1, pSvcExtendedHeader->output_flag);
|
||||
pNALU->put_bits(2, 3 /* reserved_three_2bits */);
|
||||
}
|
||||
|
||||
pNALU->flush();
|
||||
|
||||
// NAL body
|
||||
@@ -648,3 +667,57 @@ d3d12_video_nalu_writer_h264::write_sei_nalu(H264_SEI_MESSAGE sei_
|
||||
|
||||
writtenBytes = naluByteSize;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_nalu_writer_h264::write_slice_svc_prefix(const H264_SLICE_PREFIX_SVC & nal_svc_prefix,
|
||||
std::vector<uint8_t> & headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenBytes)
|
||||
{
|
||||
d3d12_video_encoder_bitstream rbsp, nalu;
|
||||
if (!rbsp.create_bitstream(2 * MAX_COMPRESSED_PPS)) {
|
||||
debug_printf("rbsp.create_bitstream(2 * MAX_COMPRESSED_PPS) failed.\n");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (!nalu.create_bitstream(2 * MAX_COMPRESSED_PPS)) {
|
||||
debug_printf("nalu.create_bitstream(2 * MAX_COMPRESSED_PPS) failed.\n");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
rbsp.set_start_code_prevention(true);
|
||||
|
||||
// prefix_nal_unit_svc ( )
|
||||
if (nal_svc_prefix.nal_ref_idc == NAL_REFIDC_REF)
|
||||
{
|
||||
rbsp.put_bits(1, nal_svc_prefix.store_ref_base_pic_flag);
|
||||
rbsp.put_bits(1, 0 /* additional_prefix_nal_unit_extension_flag */);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No more_rbsp_data( ) so we don't need to code anything else
|
||||
}
|
||||
|
||||
rbsp_trailing(&rbsp);
|
||||
rbsp.flush();
|
||||
if (wrap_rbsp_into_nalu(&nalu, &rbsp, nal_svc_prefix.nal_ref_idc, NAL_TYPE_PREFIX, &nal_svc_prefix) <= 0u) {
|
||||
|
||||
debug_printf(
|
||||
"wrap_rbsp_into_nalu(&nalu, &rbsp, NAL_REFIDC_REF, NAL_TYPE_ACCESS_UNIT_DELIMITER) didn't write any bytes.\n");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Deep copy nalu into headerBitstream, nalu gets out of scope here and its destructor frees the nalu object buffer
|
||||
// memory.
|
||||
uint8_t *naluBytes = nalu.get_bitstream_buffer();
|
||||
size_t naluByteSize = nalu.get_byte_count();
|
||||
|
||||
auto startDstIndex = std::distance(headerBitstream.begin(), placingPositionStart);
|
||||
if (headerBitstream.size() < (startDstIndex + naluByteSize)) {
|
||||
headerBitstream.resize(startDstIndex + naluByteSize);
|
||||
}
|
||||
|
||||
std::copy_n(&naluBytes[0], naluByteSize, &headerBitstream.data()[startDstIndex]);
|
||||
|
||||
writtenBytes = naluByteSize;
|
||||
}
|
||||
@@ -55,6 +55,28 @@ enum H264_NALU_TYPE
|
||||
/* 24...31 UNSPECIFIED */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// nal header
|
||||
H264_NALREF_IDC nal_ref_idc;
|
||||
|
||||
// nal_unit_header_svc_extension( )
|
||||
uint32_t idr_flag; // u(1)
|
||||
uint32_t priority_id; // u(6)
|
||||
uint32_t no_inter_layer_pred_flag; // u(1)
|
||||
uint32_t dependency_id; // u(3)
|
||||
uint32_t quality_id; // u(4)
|
||||
uint32_t temporal_id; // u(3)
|
||||
uint32_t use_ref_base_pic_flag; // u(1)
|
||||
uint32_t discardable_flag; // u(1)
|
||||
uint32_t output_flag; // u(1)
|
||||
// uint32_t reserved_three_2bits; // u(2)
|
||||
|
||||
// prefix_nal_unit_svc ( )
|
||||
uint32_t store_ref_base_pic_flag; // u(1)
|
||||
// uint32_t additional_prefix_nal_unit_extension_flag; // u(1)
|
||||
} H264_SLICE_PREFIX_SVC;
|
||||
|
||||
enum H264_SEI_TYPE
|
||||
{
|
||||
H264_SEI_SCALABILITY_INFO = 24,
|
||||
@@ -215,6 +237,11 @@ class d3d12_video_nalu_writer_h264
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenBytes);
|
||||
|
||||
void write_slice_svc_prefix(const H264_SLICE_PREFIX_SVC & nal_svc_prefix,
|
||||
std::vector<uint8_t> & headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t & writtenBytes);
|
||||
|
||||
private:
|
||||
// Writes from structure into bitstream with RBSP trailing but WITHOUT NAL unit wrap (eg. nal_idc_type, etc)
|
||||
uint32_t write_sps_bytes(d3d12_video_encoder_bitstream *pBitstream, H264_SPS *pSPS);
|
||||
@@ -231,7 +258,8 @@ class d3d12_video_nalu_writer_h264
|
||||
uint32_t wrap_rbsp_into_nalu(d3d12_video_encoder_bitstream *pNALU,
|
||||
d3d12_video_encoder_bitstream *pRBSP,
|
||||
uint32_t iNaluIdc,
|
||||
uint32_t iNaluType);
|
||||
uint32_t iNaluType,
|
||||
const H264_SLICE_PREFIX_SVC* pSvcExtendedHeader = NULL);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user