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_nalu_writer_h264.h"
25 #include <algorithm>
26
27 void
rbsp_trailing(d3d12_video_encoder_bitstream * pBitstream)28 d3d12_video_nalu_writer_h264::rbsp_trailing(d3d12_video_encoder_bitstream *pBitstream)
29 {
30 pBitstream->put_bits(1, 1);
31 int32_t iLeft = pBitstream->get_num_bits_for_byte_align();
32
33 if (iLeft) {
34 pBitstream->put_bits(iLeft, 0);
35 }
36
37 ASSERTED bool isAligned = pBitstream->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
38 assert(isAligned);
39 }
40
41 uint32_t
write_sps_bytes(d3d12_video_encoder_bitstream * pBitstream,H264_SPS * pSPS)42 d3d12_video_nalu_writer_h264::write_sps_bytes(d3d12_video_encoder_bitstream *pBitstream, H264_SPS *pSPS)
43 {
44 int32_t iBytesWritten = pBitstream->get_byte_count();
45
46 // Standard constraint to be between 0 and 31 inclusive
47 assert(pSPS->seq_parameter_set_id >= 0);
48 assert(pSPS->seq_parameter_set_id < 32);
49
50 pBitstream->put_bits(8, pSPS->profile_idc);
51 pBitstream->put_bits(6, pSPS->constraint_set_flags);
52 pBitstream->put_bits(2, 0); // reserved_zero_2bits
53 pBitstream->put_bits(8, pSPS->level_idc);
54 pBitstream->exp_Golomb_ue(pSPS->seq_parameter_set_id);
55
56 // If adding new profile support, check that the chroma_format_idc and bit depth are set correctly below
57 // for the new additions
58 assert((pSPS->profile_idc == H264_PROFILE_MAIN) ||
59 (pSPS->profile_idc == H264_PROFILE_HIGH) ||
60 (pSPS->profile_idc == H264_PROFILE_HIGH10) ||
61 (pSPS->profile_idc == H264_PROFILE_BASELINE) ||
62 (pSPS->profile_idc == H264_PROFILE_CONSTRAINED_BASELINE));
63
64 if ((pSPS->profile_idc == H264_PROFILE_HIGH) || (pSPS->profile_idc == H264_PROFILE_HIGH10)) {
65 // chroma_format_idc always 4.2.0
66 pBitstream->exp_Golomb_ue(1);
67 // Assume no separate_colour_plane_flag given chroma_format_idc = 1
68 pBitstream->exp_Golomb_ue(pSPS->bit_depth_luma_minus8);
69 pBitstream->exp_Golomb_ue(pSPS->bit_depth_chroma_minus8);
70 // qpprime_y_zero_transform_bypass_flag
71 pBitstream->put_bits(1, 0);
72 // seq_scaling_matrix_present_flag)
73 pBitstream->put_bits(1, 0);
74 }
75
76 pBitstream->exp_Golomb_ue(pSPS->log2_max_frame_num_minus4);
77
78 pBitstream->exp_Golomb_ue(pSPS->pic_order_cnt_type);
79 if (pSPS->pic_order_cnt_type == 0) {
80 pBitstream->exp_Golomb_ue(pSPS->log2_max_pic_order_cnt_lsb_minus4);
81 }
82 pBitstream->exp_Golomb_ue(pSPS->max_num_ref_frames);
83 pBitstream->put_bits(1, pSPS->gaps_in_frame_num_value_allowed_flag);
84 pBitstream->exp_Golomb_ue(pSPS->pic_width_in_mbs_minus1);
85 pBitstream->exp_Golomb_ue(pSPS->pic_height_in_map_units_minus1);
86
87 // No support for interlace in D3D12 Video Encode
88 // frame_mbs_only_flag coded as 1
89 pBitstream->put_bits(1, 1); // frame_mbs_only_flag
90 pBitstream->put_bits(1, pSPS->direct_8x8_inference_flag);
91
92 // no cropping
93 pBitstream->put_bits(1, pSPS->frame_cropping_flag); // frame_cropping_flag
94 if (pSPS->frame_cropping_flag) {
95 pBitstream->exp_Golomb_ue(pSPS->frame_cropping_rect_left_offset);
96 pBitstream->exp_Golomb_ue(pSPS->frame_cropping_rect_right_offset);
97 pBitstream->exp_Golomb_ue(pSPS->frame_cropping_rect_top_offset);
98 pBitstream->exp_Golomb_ue(pSPS->frame_cropping_rect_bottom_offset);
99 }
100
101 pBitstream->put_bits(1, pSPS->vui_parameters_present_flag);
102 if (pSPS->vui_parameters_present_flag)
103 {
104 pBitstream->put_bits(1, pSPS->vui.aspect_ratio_info_present_flag);
105 if (pSPS->vui.aspect_ratio_info_present_flag) {
106 pBitstream->put_bits(8, pSPS->vui.aspect_ratio_idc);
107 if (pSPS->vui.aspect_ratio_idc == 255 /*EXTENDED_SAR*/) {
108 pBitstream->put_bits(16, pSPS->vui.sar_width);
109 pBitstream->put_bits(16, pSPS->vui.sar_height);
110 }
111 }
112
113 pBitstream->put_bits(1, pSPS->vui.overscan_info_present_flag);
114 if (pSPS->vui.overscan_info_present_flag) {
115 pBitstream->put_bits(1, pSPS->vui.overscan_appropriate_flag);
116 }
117
118 pBitstream->put_bits(1, pSPS->vui.video_signal_type_present_flag);
119 if (pSPS->vui.video_signal_type_present_flag) {
120 pBitstream->put_bits(3, pSPS->vui.video_format);
121 pBitstream->put_bits(1, pSPS->vui.video_full_range_flag);
122 pBitstream->put_bits(1, pSPS->vui.colour_description_present_flag);
123 if (pSPS->vui.colour_description_present_flag) {
124 pBitstream->put_bits(8, pSPS->vui.colour_primaries);
125 pBitstream->put_bits(8, pSPS->vui.transfer_characteristics);
126 pBitstream->put_bits(8, pSPS->vui.matrix_coefficients);
127 }
128 }
129
130 pBitstream->put_bits(1, pSPS->vui.chroma_loc_info_present_flag);
131 if (pSPS->vui.chroma_loc_info_present_flag) {
132 pBitstream->exp_Golomb_ue(pSPS->vui.chroma_sample_loc_type_top_field);
133 pBitstream->exp_Golomb_ue(pSPS->vui.chroma_sample_loc_type_bottom_field);
134 }
135
136 pBitstream->put_bits(1, pSPS->vui.timing_info_present_flag);
137 if (pSPS->vui.timing_info_present_flag) {
138 pBitstream->put_bits(16, pSPS->vui.num_units_in_tick >> 16);
139 pBitstream->put_bits(16, pSPS->vui.num_units_in_tick & 0xffff);
140 pBitstream->put_bits(16, pSPS->vui.time_scale >> 16);
141 pBitstream->put_bits(16, pSPS->vui.time_scale & 0xffff);
142 pBitstream->put_bits(1, pSPS->vui.fixed_frame_rate_flag);
143 }
144
145 pBitstream->put_bits(1, pSPS->vui.nal_hrd_parameters_present_flag);
146 if (pSPS->vui.nal_hrd_parameters_present_flag) {
147 write_hrd(pBitstream, &pSPS->vui.nal_hrd_parameters);
148 }
149
150 pBitstream->put_bits(1, pSPS->vui.vcl_hrd_parameters_present_flag);
151 if (pSPS->vui.vcl_hrd_parameters_present_flag) {
152 write_hrd(pBitstream, &pSPS->vui.vcl_hrd_parameters);
153 }
154
155 if (pSPS->vui.nal_hrd_parameters_present_flag || pSPS->vui.vcl_hrd_parameters_present_flag) {
156 pBitstream->put_bits(1, pSPS->vui.low_delay_hrd_flag);
157 }
158
159 pBitstream->put_bits(1, pSPS->vui.pic_struct_present_flag);
160 pBitstream->put_bits(1, pSPS->vui.bitstream_restriction_flag);
161 if (pSPS->vui.bitstream_restriction_flag) {
162 pBitstream->put_bits(1, pSPS->vui.motion_vectors_over_pic_boundaries_flag);
163 pBitstream->exp_Golomb_ue(pSPS->vui.max_bytes_per_pic_denom);
164 pBitstream->exp_Golomb_ue(pSPS->vui.max_bits_per_mb_denom);
165 pBitstream->exp_Golomb_ue(pSPS->vui.log2_max_mv_length_horizontal);
166 pBitstream->exp_Golomb_ue(pSPS->vui.log2_max_mv_length_vertical);
167 pBitstream->exp_Golomb_ue(pSPS->vui.num_reorder_frames);
168 pBitstream->exp_Golomb_ue(pSPS->vui.max_dec_frame_buffering);
169 }
170 }
171
172 rbsp_trailing(pBitstream);
173 pBitstream->flush();
174
175 iBytesWritten = pBitstream->get_byte_count() - iBytesWritten;
176 return (uint32_t) iBytesWritten;
177 }
178
179 void
write_hrd(d3d12_video_encoder_bitstream * pBitstream,H264_HRD_PARAMS * pHrd)180 d3d12_video_nalu_writer_h264::write_hrd(d3d12_video_encoder_bitstream *pBitstream, H264_HRD_PARAMS *pHrd)
181 {
182 pBitstream->exp_Golomb_ue(pHrd->cpb_cnt_minus1);
183 pBitstream->put_bits(4, pHrd->bit_rate_scale);
184 pBitstream->put_bits(4, pHrd->cpb_size_scale);
185 for (uint32_t i = 0; i <= pHrd->cpb_cnt_minus1; i++) {
186 pBitstream->exp_Golomb_ue(pHrd->bit_rate_value_minus1[i]);
187 pBitstream->exp_Golomb_ue(pHrd->cpb_size_value_minus1[i]);
188 pBitstream->put_bits(1, pHrd->cbr_flag[i]);
189 }
190 pBitstream->put_bits(5, pHrd->initial_cpb_removal_delay_length_minus1);
191 pBitstream->put_bits(5, pHrd->cpb_removal_delay_length_minus1);
192 pBitstream->put_bits(5, pHrd->dpb_output_delay_length_minus1);
193 pBitstream->put_bits(5, pHrd->time_offset_length);
194 }
195
196 uint32_t
write_pps_bytes(d3d12_video_encoder_bitstream * pBitstream,H264_PPS * pPPS,BOOL bIsHighProfile)197 d3d12_video_nalu_writer_h264::write_pps_bytes(d3d12_video_encoder_bitstream *pBitstream,
198 H264_PPS * pPPS,
199 BOOL bIsHighProfile)
200 {
201 int32_t iBytesWritten = pBitstream->get_byte_count();
202
203 // Standard constraint to be between 0 and 31 inclusive
204 assert(pPPS->seq_parameter_set_id >= 0);
205 assert(pPPS->seq_parameter_set_id < 32);
206
207 // Standard constraint to be between 0 and 255 inclusive
208 assert(pPPS->pic_parameter_set_id >= 0);
209 assert(pPPS->pic_parameter_set_id < 256);
210
211 pBitstream->exp_Golomb_ue(pPPS->pic_parameter_set_id);
212 pBitstream->exp_Golomb_ue(pPPS->seq_parameter_set_id);
213 pBitstream->put_bits(1, pPPS->entropy_coding_mode_flag);
214 pBitstream->put_bits(1, pPPS->pic_order_present_flag); // bottom_field_pic_order_in_frame_present_flag
215 pBitstream->exp_Golomb_ue(0); // num_slice_groups_minus1
216
217
218 pBitstream->exp_Golomb_ue(pPPS->num_ref_idx_l0_active_minus1);
219 pBitstream->exp_Golomb_ue(pPPS->num_ref_idx_l1_active_minus1);
220 pBitstream->put_bits(1, 0); // weighted_pred_flag
221 pBitstream->put_bits(2, 0); // weighted_bipred_idc
222 pBitstream->exp_Golomb_se(0); // pic_init_qp_minus26
223 pBitstream->exp_Golomb_se(0); // pic_init_qs_minus26
224 pBitstream->exp_Golomb_se(0); // chroma_qp_index_offset
225 pBitstream->put_bits(1, 1); // deblocking_filter_control_present_flag
226 pBitstream->put_bits(1, pPPS->constrained_intra_pred_flag);
227 pBitstream->put_bits(1, 0); // redundant_pic_cnt_present_flag
228
229 if (bIsHighProfile) {
230 pBitstream->put_bits(1, pPPS->transform_8x8_mode_flag);
231 pBitstream->put_bits(1, 0); // pic_scaling_matrix_present_flag
232 pBitstream->exp_Golomb_se(0); // second_chroma_qp_index_offset
233 }
234
235 rbsp_trailing(pBitstream);
236 pBitstream->flush();
237
238 iBytesWritten = pBitstream->get_byte_count() - iBytesWritten;
239 return (uint32_t) iBytesWritten;
240 }
241
242 uint32_t
wrap_sps_nalu(d3d12_video_encoder_bitstream * pNALU,d3d12_video_encoder_bitstream * pRBSP)243 d3d12_video_nalu_writer_h264::wrap_sps_nalu(d3d12_video_encoder_bitstream *pNALU, d3d12_video_encoder_bitstream *pRBSP)
244 {
245 return wrap_rbsp_into_nalu(pNALU, pRBSP, NAL_REFIDC_REF, NAL_TYPE_SPS);
246 }
247
248 uint32_t
wrap_pps_nalu(d3d12_video_encoder_bitstream * pNALU,d3d12_video_encoder_bitstream * pRBSP)249 d3d12_video_nalu_writer_h264::wrap_pps_nalu(d3d12_video_encoder_bitstream *pNALU, d3d12_video_encoder_bitstream *pRBSP)
250 {
251 return wrap_rbsp_into_nalu(pNALU, pRBSP, NAL_REFIDC_REF, NAL_TYPE_PPS);
252 }
253
254 void
write_nalu_end(d3d12_video_encoder_bitstream * pNALU)255 d3d12_video_nalu_writer_h264::write_nalu_end(d3d12_video_encoder_bitstream *pNALU)
256 {
257 pNALU->flush();
258 pNALU->set_start_code_prevention(false);
259 int32_t iNALUnitLen = pNALU->get_byte_count();
260
261 if (false == pNALU->m_bBufferOverflow && 0x00 == pNALU->get_bitstream_buffer()[iNALUnitLen - 1]) {
262 pNALU->put_bits(8, 0x03);
263 pNALU->flush();
264 }
265 }
266
267 uint32_t
wrap_rbsp_into_nalu(d3d12_video_encoder_bitstream * pNALU,d3d12_video_encoder_bitstream * pRBSP,uint32_t iNaluIdc,uint32_t iNaluType)268 d3d12_video_nalu_writer_h264::wrap_rbsp_into_nalu(d3d12_video_encoder_bitstream *pNALU,
269 d3d12_video_encoder_bitstream *pRBSP,
270 uint32_t iNaluIdc,
271 uint32_t iNaluType)
272 {
273 bool isAligned = pRBSP->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
274 assert(isAligned);
275
276 int32_t iBytesWritten = pNALU->get_byte_count();
277
278 pNALU->set_start_code_prevention(false);
279
280 // NAL start code
281 pNALU->put_bits(24, 0);
282 pNALU->put_bits(8, 1);
283
284 // NAL header
285 pNALU->put_bits(1, 0);
286 pNALU->put_bits(2, iNaluIdc);
287 pNALU->put_bits(5, iNaluType);
288 pNALU->flush();
289
290 // NAL body
291 pRBSP->flush();
292
293 if (pRBSP->get_start_code_prevention_status()) {
294 // Direct copying.
295 pNALU->append_byte_stream(pRBSP);
296 } else {
297 // Copy with start code prevention.
298 pNALU->set_start_code_prevention(true);
299 int32_t iLength = pRBSP->get_byte_count();
300 uint8_t *pBuffer = pRBSP->get_bitstream_buffer();
301
302 for (int32_t i = 0; i < iLength; i++) {
303 pNALU->put_bits(8, pBuffer[i]);
304 }
305 }
306
307 isAligned = pNALU->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
308 assert(isAligned);
309 write_nalu_end(pNALU);
310
311 pNALU->flush();
312
313 iBytesWritten = pNALU->get_byte_count() - iBytesWritten;
314 return (uint32_t) iBytesWritten;
315 }
316
317 void
sps_to_nalu_bytes(H264_SPS * pSPS,std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)318 d3d12_video_nalu_writer_h264::sps_to_nalu_bytes(H264_SPS * pSPS,
319 std::vector<uint8_t> & headerBitstream,
320 std::vector<uint8_t>::iterator placingPositionStart,
321 size_t & writtenBytes)
322 {
323 // Wrap SPS into NALU and copy full NALU into output byte array
324 d3d12_video_encoder_bitstream rbsp, nalu;
325
326 if (!rbsp.create_bitstream(MAX_COMPRESSED_SPS)) {
327 debug_printf("rbsp.create_bitstream(MAX_COMPRESSED_SPS) failed\n");
328 assert(false);
329 }
330
331 if (!nalu.create_bitstream(2 * MAX_COMPRESSED_SPS)) {
332 debug_printf("nalu.create_bitstream(2 * MAX_COMPRESSED_SPS) failed\n");
333 assert(false);
334 }
335
336 rbsp.set_start_code_prevention(true);
337 if (write_sps_bytes(&rbsp, pSPS) <= 0u) {
338 debug_printf("write_sps_bytes(&rbsp, pSPS) didn't write any bytes.\n");
339 assert(false);
340 }
341
342 if (wrap_sps_nalu(&nalu, &rbsp) <= 0u) {
343 debug_printf("wrap_sps_nalu(&nalu, &rbsp) didn't write any bytes.\n");
344 assert(false);
345 }
346
347 // Deep copy nalu into headerBitstream, nalu gets out of scope here and its destructor frees the nalu object buffer
348 // memory.
349 uint8_t *naluBytes = nalu.get_bitstream_buffer();
350 size_t naluByteSize = nalu.get_byte_count();
351
352 auto startDstIndex = std::distance(headerBitstream.begin(), placingPositionStart);
353 if (headerBitstream.size() < (startDstIndex + naluByteSize)) {
354 headerBitstream.resize(startDstIndex + naluByteSize);
355 }
356
357 std::copy_n(&naluBytes[0], naluByteSize, &headerBitstream.data()[startDstIndex]);
358
359 writtenBytes = naluByteSize;
360 }
361
362 void
pps_to_nalu_bytes(H264_PPS * pPPS,std::vector<uint8_t> & headerBitstream,BOOL bIsHighProfile,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)363 d3d12_video_nalu_writer_h264::pps_to_nalu_bytes(H264_PPS * pPPS,
364 std::vector<uint8_t> & headerBitstream,
365 BOOL bIsHighProfile,
366 std::vector<uint8_t>::iterator placingPositionStart,
367 size_t & writtenBytes)
368 {
369 // Wrap PPS into NALU and copy full NALU into output byte array
370 d3d12_video_encoder_bitstream rbsp, nalu;
371 if (!rbsp.create_bitstream(MAX_COMPRESSED_PPS)) {
372 debug_printf("rbsp.create_bitstream(MAX_COMPRESSED_PPS) failed\n");
373 assert(false);
374 }
375
376 if (!nalu.create_bitstream(2 * MAX_COMPRESSED_PPS)) {
377 debug_printf("nalu.create_bitstream(2 * MAX_COMPRESSED_PPS) failed\n");
378 assert(false);
379 }
380
381 rbsp.set_start_code_prevention(true);
382
383 if (write_pps_bytes(&rbsp, pPPS, bIsHighProfile) <= 0u) {
384 debug_printf("write_pps_bytes(&rbsp, pPPS, bIsHighProfile) didn't write any bytes.\n");
385 assert(false);
386 }
387
388 if (wrap_pps_nalu(&nalu, &rbsp) <= 0u) {
389 debug_printf("wrap_pps_nalu(&nalu, &rbsp) didn't write any bytes.\n");
390 assert(false);
391 }
392
393 // Deep copy nalu into headerBitstream, nalu gets out of scope here and its destructor frees the nalu object buffer
394 // memory.
395 uint8_t *naluBytes = nalu.get_bitstream_buffer();
396 size_t naluByteSize = nalu.get_byte_count();
397
398 auto startDstIndex = std::distance(headerBitstream.begin(), placingPositionStart);
399 if (headerBitstream.size() < (startDstIndex + naluByteSize)) {
400 headerBitstream.resize(startDstIndex + naluByteSize);
401 }
402
403 std::copy_n(&naluBytes[0], naluByteSize, &headerBitstream.data()[startDstIndex]);
404
405 writtenBytes = naluByteSize;
406 }
407
408 void
write_end_of_stream_nalu(std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)409 d3d12_video_nalu_writer_h264::write_end_of_stream_nalu(std::vector<uint8_t> & headerBitstream,
410 std::vector<uint8_t>::iterator placingPositionStart,
411 size_t & writtenBytes)
412 {
413 d3d12_video_encoder_bitstream rbsp, nalu;
414 if (!rbsp.create_bitstream(8)) {
415 debug_printf("rbsp.create_bitstream(8) failed\n");
416 assert(false);
417 }
418 if (!nalu.create_bitstream(2 * MAX_COMPRESSED_PPS)) {
419 debug_printf("nalu.create_bitstream(2 * MAX_COMPRESSED_PPS) failed\n");
420 assert(false);
421 }
422
423 rbsp.set_start_code_prevention(true);
424 if (wrap_rbsp_into_nalu(&nalu, &rbsp, NAL_REFIDC_REF, NAL_TYPE_END_OF_STREAM) <= 0u) {
425 debug_printf(
426 "wrap_rbsp_into_nalu(&nalu, &rbsp, NAL_REFIDC_REF, NAL_TYPE_END_OF_STREAM) didn't write any bytes.\n");;
427 assert(false);
428 }
429
430 // Deep copy nalu into headerBitstream, nalu gets out of scope here and its destructor frees the nalu object buffer
431 // memory.
432 uint8_t *naluBytes = nalu.get_bitstream_buffer();
433 size_t naluByteSize = nalu.get_byte_count();
434
435 auto startDstIndex = std::distance(headerBitstream.begin(), placingPositionStart);
436 if (headerBitstream.size() < (startDstIndex + naluByteSize)) {
437 headerBitstream.resize(startDstIndex + naluByteSize);
438 }
439
440 std::copy_n(&naluBytes[0], naluByteSize, &headerBitstream.data()[startDstIndex]);
441
442 writtenBytes = naluByteSize;
443 }
444
445 void
write_end_of_sequence_nalu(std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)446 d3d12_video_nalu_writer_h264::write_end_of_sequence_nalu(std::vector<uint8_t> & headerBitstream,
447 std::vector<uint8_t>::iterator placingPositionStart,
448 size_t & writtenBytes)
449 {
450 d3d12_video_encoder_bitstream rbsp, nalu;
451 if (!rbsp.create_bitstream(8)) {
452 debug_printf("rbsp.create_bitstream(8) failed.\n");
453 assert(false);
454 }
455
456 if (!nalu.create_bitstream(2 * MAX_COMPRESSED_PPS)) {
457 debug_printf("nalu.create_bitstream(2 * MAX_COMPRESSED_PPS) failed.\n");
458 assert(false);
459 }
460
461 rbsp.set_start_code_prevention(true);
462 if (wrap_rbsp_into_nalu(&nalu, &rbsp, NAL_REFIDC_REF, NAL_TYPE_END_OF_SEQUENCE) <= 0u) {
463
464 debug_printf(
465 "wrap_rbsp_into_nalu(&nalu, &rbsp, NAL_REFIDC_REF, NAL_TYPE_END_OF_SEQUENCE) didn't write any bytes.\n");
466 assert(false);
467 }
468
469 // Deep copy nalu into headerBitstream, nalu gets out of scope here and its destructor frees the nalu object buffer
470 // memory.
471 uint8_t *naluBytes = nalu.get_bitstream_buffer();
472 size_t naluByteSize = nalu.get_byte_count();
473
474 auto startDstIndex = std::distance(headerBitstream.begin(), placingPositionStart);
475 if (headerBitstream.size() < (startDstIndex + naluByteSize)) {
476 headerBitstream.resize(startDstIndex + naluByteSize);
477 }
478
479 std::copy_n(&naluBytes[0], naluByteSize, &headerBitstream.data()[startDstIndex]);
480
481 writtenBytes = naluByteSize;
482 }
483
484 void
write_access_unit_delimiter_nalu(std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenBytes)485 d3d12_video_nalu_writer_h264::write_access_unit_delimiter_nalu(std::vector<uint8_t> & headerBitstream,
486 std::vector<uint8_t>::iterator placingPositionStart,
487 size_t & writtenBytes)
488 {
489 d3d12_video_encoder_bitstream rbsp, nalu;
490 if (!rbsp.create_bitstream(8)) {
491 debug_printf("rbsp.create_bitstream(8) failed.\n");
492 assert(false);
493 }
494
495 if (!nalu.create_bitstream(2 * MAX_COMPRESSED_PPS)) {
496 debug_printf("nalu.create_bitstream(2 * MAX_COMPRESSED_PPS) failed.\n");
497 assert(false);
498 }
499
500 rbsp.set_start_code_prevention(true);
501 rbsp.put_bits(3, 2/*primary_pic_type*/);
502 rbsp_trailing(&rbsp);
503 rbsp.flush();
504 if (wrap_rbsp_into_nalu(&nalu, &rbsp, NAL_REFIDC_NONREF, NAL_TYPE_ACCESS_UNIT_DELIMITER) <= 0u) {
505
506 debug_printf(
507 "wrap_rbsp_into_nalu(&nalu, &rbsp, NAL_REFIDC_NONREF, NAL_TYPE_ACCESS_UNIT_DELIMITER) didn't write any bytes.\n");
508 assert(false);
509 }
510
511 // Deep copy nalu into headerBitstream, nalu gets out of scope here and its destructor frees the nalu object buffer
512 // memory.
513 uint8_t *naluBytes = nalu.get_bitstream_buffer();
514 size_t naluByteSize = nalu.get_byte_count();
515
516 auto startDstIndex = std::distance(headerBitstream.begin(), placingPositionStart);
517 if (headerBitstream.size() < (startDstIndex + naluByteSize)) {
518 headerBitstream.resize(startDstIndex + naluByteSize);
519 }
520
521 std::copy_n(&naluBytes[0], naluByteSize, &headerBitstream.data()[startDstIndex]);
522
523 writtenBytes = naluByteSize;
524 }
525