xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_video_encoder_nalu_writer_h264.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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