• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © Microsoft Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "d3d12_video_encoder_bitstream_builder_h264.h"
25 
26 #include <cmath>
27 
28 inline H264_SPEC_PROFILES
Convert12ToSpecH264Profiles(D3D12_VIDEO_ENCODER_PROFILE_H264 profile12)29 Convert12ToSpecH264Profiles(D3D12_VIDEO_ENCODER_PROFILE_H264 profile12)
30 {
31    switch (profile12) {
32       case D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN:
33       {
34          return H264_PROFILE_MAIN;
35       } break;
36       case D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH:
37       {
38          return H264_PROFILE_HIGH;
39       } break;
40       case D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH_10:
41       {
42          return H264_PROFILE_HIGH10;
43       } break;
44       default:
45       {
46          unreachable("Unsupported D3D12_VIDEO_ENCODER_PROFILE_H264");
47       } break;
48    }
49 }
50 
51 void
build_sps(const D3D12_VIDEO_ENCODER_PROFILE_H264 & profile,const D3D12_VIDEO_ENCODER_LEVELS_H264 & level,const DXGI_FORMAT & inputFmt,const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 & codecConfig,const D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 & gopConfig,uint32_t seq_parameter_set_id,uint32_t max_num_ref_frames,D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC sequenceTargetResolution,D3D12_BOX frame_cropping_codec_config,std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)52 d3d12_video_bitstream_builder_h264::build_sps(const D3D12_VIDEO_ENCODER_PROFILE_H264 &               profile,
53                                               const D3D12_VIDEO_ENCODER_LEVELS_H264 &                level,
54                                               const DXGI_FORMAT &                                    inputFmt,
55                                               const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 &   codecConfig,
56                                               const D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 &gopConfig,
57                                               uint32_t                                    seq_parameter_set_id,
58                                               uint32_t                                    max_num_ref_frames,
59                                               D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC sequenceTargetResolution,
60                                               D3D12_BOX                                   frame_cropping_codec_config,
61                                               std::vector<uint8_t> &                      headerBitstream,
62                                               std::vector<uint8_t>::iterator              placingPositionStart,
63                                               size_t &                                    writtenBytes)
64 {
65    H264_SPEC_PROFILES profile_idc          = Convert12ToSpecH264Profiles(profile);
66    uint32_t           constraint_set3_flag = 0;
67    uint32_t           level_idc            = 0;
68    d3d12_video_encoder_convert_from_d3d12_level_h264(
69       level,
70       level_idc,
71       constraint_set3_flag /*Always 0 except if level is 11 or 1b in which case 0 means 11, 1 means 1b*/);
72 
73    // constraint_set3_flag is for Main profile only and levels 11 or 1b: levels 11 if off, level 1b if on. Always 0 for
74    // HIGH/HIGH10 profiles
75    if ((profile == D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH) || (profile == D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH_10)) {
76       // Force 0 for high profiles
77       constraint_set3_flag = 0;
78    }
79 
80    assert((inputFmt == DXGI_FORMAT_NV12) || (inputFmt == DXGI_FORMAT_P010));
81 
82    // Assume NV12 YUV 420 8 bits
83    uint32_t bit_depth_luma_minus8   = 0;
84    uint32_t bit_depth_chroma_minus8 = 0;
85 
86    // In case is 420 10 bits fix it
87    if (inputFmt == DXGI_FORMAT_P010) {
88       bit_depth_luma_minus8   = 2;
89       bit_depth_chroma_minus8 = 2;
90    }
91 
92    // Calculate sequence resolution sizes in MBs
93    // Always in MBs since we don't support interlace in D3D12 Encode
94    uint32_t pic_width_in_mbs_minus1 = static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Width / 16.0)) - 1;
95    uint32_t pic_height_in_map_units_minus1 =
96       static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Height / 16.0)) - 1;
97 
98    uint32_t frame_cropping_flag               = 0;
99    if (frame_cropping_codec_config.left
100       || frame_cropping_codec_config.right
101       || frame_cropping_codec_config.top
102       || frame_cropping_codec_config.bottom
103    ) {
104       frame_cropping_flag               = 1;
105    }
106 
107    H264_SPS spsStructure = { static_cast<uint32_t>(profile_idc),
108                              constraint_set3_flag,
109                              level_idc,
110                              seq_parameter_set_id,
111                              bit_depth_luma_minus8,
112                              bit_depth_chroma_minus8,
113                              gopConfig.log2_max_frame_num_minus4,
114                              gopConfig.pic_order_cnt_type,
115                              gopConfig.log2_max_pic_order_cnt_lsb_minus4,
116                              max_num_ref_frames,
117                              0,   // gaps_in_frame_num_value_allowed_flag
118                              pic_width_in_mbs_minus1,
119                              pic_height_in_map_units_minus1,
120                              ((codecConfig.ConfigurationFlags &
121                                D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_ADAPTIVE_8x8_TRANSFORM) != 0) ?
122                                 1u :
123                                 0u,   // direct_8x8_inference_flag
124                              frame_cropping_flag,
125                              frame_cropping_codec_config.left,
126                              frame_cropping_codec_config.right,
127                              frame_cropping_codec_config.top,
128                              frame_cropping_codec_config.bottom };
129 
130    // Print built PPS structure
131    debug_printf(
132       "[D3D12 d3d12_video_bitstream_builder_h264] H264_SPS Structure generated before writing to bitstream:\n");
133    print_sps(spsStructure);
134 
135    // Convert the H264 SPS structure into bytes
136    m_h264Encoder.sps_to_nalu_bytes(&spsStructure, headerBitstream, placingPositionStart, writtenBytes);
137 }
138 
139 void
write_end_of_stream_nalu(std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)140 d3d12_video_bitstream_builder_h264::write_end_of_stream_nalu(std::vector<uint8_t> &         headerBitstream,
141                                                              std::vector<uint8_t>::iterator placingPositionStart,
142                                                              size_t &                       writtenBytes)
143 {
144    m_h264Encoder.write_end_of_stream_nalu(headerBitstream, placingPositionStart, writtenBytes);
145 }
146 
147 void
write_end_of_sequence_nalu(std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)148 d3d12_video_bitstream_builder_h264::write_end_of_sequence_nalu(std::vector<uint8_t> &         headerBitstream,
149                                                                std::vector<uint8_t>::iterator placingPositionStart,
150                                                                size_t &                       writtenBytes)
151 {
152    m_h264Encoder.write_end_of_sequence_nalu(headerBitstream, placingPositionStart, writtenBytes);
153 }
154 
155 void
build_pps(const D3D12_VIDEO_ENCODER_PROFILE_H264 & profile,const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 & codecConfig,const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 & pictureControl,uint32_t pic_parameter_set_id,uint32_t seq_parameter_set_id,std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)156 d3d12_video_bitstream_builder_h264::build_pps(const D3D12_VIDEO_ENCODER_PROFILE_H264 &                   profile,
157                                               const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 &       codecConfig,
158                                               const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 &pictureControl,
159                                               uint32_t                       pic_parameter_set_id,
160                                               uint32_t                       seq_parameter_set_id,
161                                               std::vector<uint8_t> &         headerBitstream,
162                                               std::vector<uint8_t>::iterator placingPositionStart,
163                                               size_t &                       writtenBytes)
164 {
165    BOOL bIsHighProfile =
166       ((profile == D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH) || (profile == D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH_10));
167 
168    H264_PPS ppsStructure = {
169       pic_parameter_set_id,
170       seq_parameter_set_id,
171       ((codecConfig.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING) != 0) ?
172          1u :
173          0u,   // entropy_coding_mode_flag
174       0,   // pic_order_present_flag (bottom_field_pic_order_in_frame_present_flag) - will use pic_cnt 0 or 2, always
175            // off ; used with pic_cnt_type 1 and deltas.
176       static_cast<uint32_t>(std::max(static_cast<int32_t>(pictureControl.List0ReferenceFramesCount) - 1,
177                                      0)),   // num_ref_idx_l0_active_minus1
178       static_cast<uint32_t>(std::max(static_cast<int32_t>(pictureControl.List1ReferenceFramesCount) - 1,
179                                      0)),   // num_ref_idx_l1_active_minus1
180       ((codecConfig.ConfigurationFlags &
181         D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_CONSTRAINED_INTRAPREDICTION) != 0) ?
182          1u :
183          0u,   // constrained_intra_pred_flag
184       ((codecConfig.ConfigurationFlags &
185         D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_ADAPTIVE_8x8_TRANSFORM) != 0) ?
186          1u :
187          0u   // transform_8x8_mode_flag
188    };
189 
190    // Print built PPS structure
191    debug_printf(
192       "[D3D12 d3d12_video_bitstream_builder_h264] H264_PPS Structure generated before writing to bitstream:\n");
193    print_pps(ppsStructure);
194 
195    // Convert the H264 SPS structure into bytes
196    m_h264Encoder.pps_to_nalu_bytes(&ppsStructure, headerBitstream, bIsHighProfile, placingPositionStart, writtenBytes);
197 }
198 
199 void
print_pps(const H264_PPS & pps)200 d3d12_video_bitstream_builder_h264::print_pps(const H264_PPS &pps)
201 {
202    // Be careful that build_pps also wraps some other NALU bytes in pps_to_nalu_bytes so bitstream returned by build_pps
203    // won't be exactly the bytes from the H264_PPS struct
204 
205    static_assert(sizeof(H264_PPS) ==
206                  (sizeof(uint32_t) *
207                   8), "Update the number of uint32_t in struct in assert and add case below if structure changes");
208 
209    // Declared fields from definition in d3d12_video_encoder_bitstream_builder_h264.h
210 
211    debug_printf("[D3D12 d3d12_video_bitstream_builder_h264] H264_PPS values below:\n");
212    debug_printf("pic_parameter_set_id: %d\n", pps.pic_parameter_set_id);
213    debug_printf("seq_parameter_set_id: %d\n", pps.seq_parameter_set_id);
214    debug_printf("entropy_coding_mode_flag: %d\n", pps.entropy_coding_mode_flag);
215    debug_printf("pic_order_present_flag: %d\n", pps.pic_order_present_flag);
216    debug_printf("num_ref_idx_l0_active_minus1: %d\n", pps.num_ref_idx_l0_active_minus1);
217    debug_printf("num_ref_idx_l1_active_minus1: %d\n", pps.num_ref_idx_l1_active_minus1);
218    debug_printf("constrained_intra_pred_flag: %d\n", pps.constrained_intra_pred_flag);
219    debug_printf("transform_8x8_mode_flag: %d\n", pps.transform_8x8_mode_flag);
220    debug_printf(
221       "[D3D12 d3d12_video_bitstream_builder_h264] H264_PPS values end\n--------------------------------------\n");
222 }
223 
224 void
print_sps(const H264_SPS & sps)225 d3d12_video_bitstream_builder_h264::print_sps(const H264_SPS &sps)
226 {
227    // Be careful when calling this method that build_sps also wraps some other NALU bytes in sps_to_nalu_bytes so
228    // bitstream returned by build_sps won't be exactly the bytes from the H264_SPS struct From definition in
229    // d3d12_video_encoder_bitstream_builder_h264.h
230 
231    static_assert(sizeof(H264_SPS) ==
232                  (sizeof(uint32_t) *
233                   19), "Update the number of uint32_t in struct in assert and add case below if structure changes");
234 
235    // Declared fields from definition in d3d12_video_encoder_bitstream_builder_h264.h
236 
237    debug_printf("[D3D12 d3d12_video_bitstream_builder_h264] H264_SPS values below:\n");
238    debug_printf("profile_idc: %d\n", sps.profile_idc);
239    debug_printf("constraint_set3_flag: %d\n", sps.constraint_set3_flag);
240    debug_printf("level_idc: %d\n", sps.level_idc);
241    debug_printf("seq_parameter_set_id: %d\n", sps.seq_parameter_set_id);
242    debug_printf("bit_depth_luma_minus8: %d\n", sps.bit_depth_luma_minus8);
243    debug_printf("bit_depth_chroma_minus8: %d\n", sps.bit_depth_chroma_minus8);
244    debug_printf("log2_max_frame_num_minus4: %d\n", sps.log2_max_frame_num_minus4);
245    debug_printf("pic_order_cnt_type: %d\n", sps.pic_order_cnt_type);
246    debug_printf("log2_max_pic_order_cnt_lsb_minus4: %d\n", sps.log2_max_pic_order_cnt_lsb_minus4);
247    debug_printf("max_num_ref_frames: %d\n", sps.max_num_ref_frames);
248    debug_printf("gaps_in_frame_num_value_allowed_flag: %d\n", sps.gaps_in_frame_num_value_allowed_flag);
249    debug_printf("pic_width_in_mbs_minus1: %d\n", sps.pic_width_in_mbs_minus1);
250    debug_printf("pic_height_in_map_units_minus1: %d\n", sps.pic_height_in_map_units_minus1);
251    debug_printf("direct_8x8_inference_flag: %d\n", sps.direct_8x8_inference_flag);
252    debug_printf("frame_cropping_flag: %d\n", sps.frame_cropping_flag);
253    debug_printf("frame_cropping_rect_left_offset: %d\n", sps.frame_cropping_rect_left_offset);
254    debug_printf("frame_cropping_rect_right_offset: %d\n", sps.frame_cropping_rect_right_offset);
255    debug_printf("frame_cropping_rect_top_offset: %d\n", sps.frame_cropping_rect_top_offset);
256    debug_printf("frame_cropping_rect_bottom_offset: %d\n", sps.frame_cropping_rect_bottom_offset);
257    debug_printf(
258       "[D3D12 d3d12_video_bitstream_builder_h264] H264_SPS values end\n--------------------------------------\n");
259 }
260