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_references_manager_h264.h"
25 #include <algorithm>
26 #include <string>
27 #include "d3d12_screen.h"
28
29 using namespace std;
30
d3d12_video_encoder_references_manager_h264(bool gopHasIorPFrames,d3d12_video_dpb_storage_manager_interface & rDpbStorageManager,uint32_t MaxDPBCapacity)31 d3d12_video_encoder_references_manager_h264::d3d12_video_encoder_references_manager_h264(
32 bool gopHasIorPFrames, d3d12_video_dpb_storage_manager_interface &rDpbStorageManager, uint32_t MaxDPBCapacity)
33 : m_MaxDPBCapacity(MaxDPBCapacity),
34 m_rDPBStorageManager(rDpbStorageManager),
35 m_CurrentFrameReferencesData({}),
36 m_gopHasInterFrames(gopHasIorPFrames)
37 {
38 assert((m_MaxDPBCapacity + 1 /*extra for cur frame output recon pic*/) ==
39 m_rDPBStorageManager.get_number_of_tracked_allocations());
40
41 debug_printf("[D3D12 Video Encoder Picture Manager H264] Completed construction of "
42 "d3d12_video_encoder_references_manager_h264 instance, settings are\n");
43 debug_printf("[D3D12 Video Encoder Picture Manager H264] m_MaxDPBCapacity: %d\n", m_MaxDPBCapacity);
44 }
45
46 void
reset_gop_tracking_and_dpb()47 d3d12_video_encoder_references_manager_h264::reset_gop_tracking_and_dpb()
48 {
49 // Reset m_CurrentFrameReferencesData tracking
50 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.clear();
51 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.reserve(m_MaxDPBCapacity);
52 m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
53
54 // Reset DPB storage
55 uint32_t numPicsBeforeClearInDPB = m_rDPBStorageManager.get_number_of_pics_in_dpb();
56 uint32_t cFreedResources = m_rDPBStorageManager.clear_decode_picture_buffer();
57 assert(numPicsBeforeClearInDPB == cFreedResources);
58
59 // Initialize if needed the reconstructed picture allocation for the first IDR picture in the GOP
60 // This needs to be done after initializing the GOP tracking state above since it makes decisions based on the
61 // current picture type.
62 prepare_current_frame_recon_pic_allocation();
63
64 // After clearing the DPB, outstanding used allocations should be 1u only for the first allocation for the
65 // reconstructed picture of the initial IDR in the GOP
66 assert(m_rDPBStorageManager.get_number_of_in_use_allocations() == (m_gopHasInterFrames ? 1u : 0u));
67 assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <=
68 (m_MaxDPBCapacity + 1)); // pool is not extended beyond maximum expected usage
69 }
70
71 // Calculates the picture control structure for the current frame
72 void
get_current_frame_picture_control_data(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA & codecAllocation)73 d3d12_video_encoder_references_manager_h264::get_current_frame_picture_control_data(
74 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation)
75 {
76 // Update reference picture control structures (L0/L1 and DPB descriptors lists based on current frame and next frame
77 // in GOP) for next frame
78
79 debug_printf("[D3D12 Video Encoder Picture Manager H264] %d resources IN USE out of a total of %d ALLOCATED "
80 "resources at frame with POC: %d\n",
81 m_rDPBStorageManager.get_number_of_in_use_allocations(),
82 m_rDPBStorageManager.get_number_of_tracked_allocations(),
83 m_curFrameState.PictureOrderCountNumber);
84
85 // See casts below
86 assert(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size() < UINT32_MAX);
87
88 bool needsL0List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) ||
89 (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME);
90 bool needsL1List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME);
91
92 assert(codecAllocation.DataSize == sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264));
93
94 // See D3D12 Encode spec below
95 // pList0ReferenceFrames
96 // List of past frame reference frames to be used for this frame. Each integer value in this array indices into
97 // pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
98 // pList1ReferenceFrames
99 // List of future frame reference frames to be used for this frame. Each integer value in this array indices into
100 // pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
101
102 // Need to map from frame_num in the receiving ref_idx_l0_list/ref_idx_l1_list to the position with that
103 // FrameDecodingOrderNumber in the DPB descriptor
104
105 if (needsL0List && (m_curFrameState.List0ReferenceFramesCount > 0)) {
106 std::vector<uint32_t> tmpL0(m_curFrameState.List0ReferenceFramesCount, 0);
107 memcpy(tmpL0.data(),
108 m_curFrameState.pList0ReferenceFrames,
109 m_curFrameState.List0ReferenceFramesCount * sizeof(m_curFrameState.pList0ReferenceFrames[0]));
110
111 for (size_t l0Idx = 0; l0Idx < m_curFrameState.List0ReferenceFramesCount; l0Idx++) {
112 // tmpL0[l0Idx] has frame_num's (FrameDecodingOrderNumber)
113 // m_curFrameState.pList0ReferenceFrames[l0Idx] needs to have the index j of
114 // pReferenceFramesReconPictureDescriptors where
115 // pReferenceFramesReconPictureDescriptors[j].FrameDecodingOrderNumber == tmpL0[l0Idx]
116
117 auto value = tmpL0[l0Idx];
118 auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
119 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
120 [&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 &p) {
121 return p.FrameDecodingOrderNumber == value;
122 });
123
124 assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
125 m_curFrameState.pList0ReferenceFrames[l0Idx] =
126 std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
127 }
128 }
129
130 if (needsL1List && (m_curFrameState.List1ReferenceFramesCount > 0)) {
131 std::vector<uint32_t> tmpL1(m_curFrameState.List1ReferenceFramesCount, 0);
132 memcpy(tmpL1.data(),
133 m_curFrameState.pList1ReferenceFrames,
134 m_curFrameState.List1ReferenceFramesCount * sizeof(m_curFrameState.pList1ReferenceFrames[0]));
135
136 for (size_t l1Idx = 0; l1Idx < m_curFrameState.List1ReferenceFramesCount; l1Idx++) {
137 // tmpL1[l1Idx] has frame_num's (FrameDecodingOrderNumber)
138 // m_curFrameState.pList1ReferenceFrames[l1Idx] needs to have the index j of
139 // pReferenceFramesReconPictureDescriptors where
140 // pReferenceFramesReconPictureDescriptors[j].FrameDecodingOrderNumber == tmpL1[l1Idx]
141
142 auto value = tmpL1[l1Idx];
143 auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
144 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
145 [&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 &p) {
146 return p.FrameDecodingOrderNumber == value;
147 });
148
149 assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
150 m_curFrameState.pList1ReferenceFrames[l1Idx] =
151 std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
152 }
153 }
154
155 m_curFrameState.List0ReferenceFramesCount = needsL0List ? m_curFrameState.List0ReferenceFramesCount : 0;
156 m_curFrameState.pList0ReferenceFrames = needsL0List ? m_curFrameState.pList0ReferenceFrames : nullptr,
157 m_curFrameState.List1ReferenceFramesCount = needsL1List ? m_curFrameState.List1ReferenceFramesCount : 0,
158 m_curFrameState.pList1ReferenceFrames = needsL1List ? m_curFrameState.pList1ReferenceFrames : nullptr,
159 m_curFrameState.ReferenceFramesReconPictureDescriptorsCount =
160 needsL0List ? static_cast<uint32_t>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size()) :
161 0,
162 m_curFrameState.pReferenceFramesReconPictureDescriptors =
163 needsL0List ? m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.data() : nullptr,
164
165 *codecAllocation.pH264PicData = m_curFrameState;
166
167 print_l0_l1_lists();
168 print_dpb();
169 }
170
171 // Returns the resource allocation for a reconstructed picture output for the current frame
172 D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE
get_current_frame_recon_pic_output_allocation()173 d3d12_video_encoder_references_manager_h264::get_current_frame_recon_pic_output_allocation()
174 {
175 return m_CurrentFrameReferencesData.ReconstructedPicTexture;
176 }
177
178 D3D12_VIDEO_ENCODE_REFERENCE_FRAMES
get_current_reference_frames()179 d3d12_video_encoder_references_manager_h264::get_current_reference_frames()
180 {
181 D3D12_VIDEO_ENCODE_REFERENCE_FRAMES retVal = { 0,
182 // ppTexture2Ds
183 nullptr,
184 // pSubresources
185 nullptr };
186
187 // Return nullptr for fully intra frames (eg IDR)
188 // and return references information for inter frames (eg.P/B) and I frame that doesn't flush DPB
189
190 if ((m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME) &&
191 (m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME) && m_gopHasInterFrames) {
192 auto curRef = m_rDPBStorageManager.get_current_reference_frames();
193 retVal.NumTexture2Ds = curRef.NumTexture2Ds;
194 retVal.ppTexture2Ds = curRef.ppTexture2Ds;
195 retVal.pSubresources = curRef.pSubresources;
196 }
197
198 return retVal;
199 }
200
201 void
prepare_current_frame_recon_pic_allocation()202 d3d12_video_encoder_references_manager_h264::prepare_current_frame_recon_pic_allocation()
203 {
204 m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
205
206 // If all GOP are intra frames, no point in doing reference pic allocations
207 if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
208 auto reconPic = m_rDPBStorageManager.get_new_tracked_picture_allocation();
209 m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture = reconPic.pReconstructedPicture;
210 m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource =
211 reconPic.ReconstructedPictureSubresource;
212 }
213 }
214
215 void
update_fifo_dpb_push_front_cur_recon_pic()216 d3d12_video_encoder_references_manager_h264::update_fifo_dpb_push_front_cur_recon_pic()
217 {
218 // Keep the order of the dpb storage and dpb descriptors in a circular buffer
219 // order such that the DPB array consists of a sequence of frames in DECREASING encoding order
220 // eg. last frame encoded at first, followed by one to last frames encoded, and at the end
221 // the most distant frame encoded (currentFrameEncodeOrderNumber - MaxDPBSize)
222
223 // If current pic was not used as reference, current reconstructed picture resource is empty,
224 // No need to to anything in that case.
225 // Otherwise extract the reconstructed picture result and add it to the DPB
226
227 // If GOP are all intra frames, do nothing also.
228 if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
229 debug_printf("[D3D12 Video Encoder Picture Manager H264] MaxDPBCapacity is %d - Number of pics in DPB is %d "
230 "when trying to put frame with POC %d at front of the DPB\n",
231 m_MaxDPBCapacity,
232 m_rDPBStorageManager.get_number_of_pics_in_dpb(),
233 m_curFrameState.PictureOrderCountNumber);
234
235 // Release least recently used in DPB if we filled the m_MaxDPBCapacity allowed
236 if (m_rDPBStorageManager.get_number_of_pics_in_dpb() == m_MaxDPBCapacity) {
237 bool untrackedRes = false;
238 m_rDPBStorageManager.remove_reference_frame(m_rDPBStorageManager.get_number_of_pics_in_dpb() - 1,
239 &untrackedRes); // Remove last entry
240 // Verify that resource was untracked since this class is using the pool completely for allocations
241 assert(untrackedRes);
242 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.pop_back(); // Remove last entry
243 }
244
245 // Add new dpb to front of DPB
246 D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE recAlloc = get_current_frame_recon_pic_output_allocation();
247 d3d12_video_reconstructed_picture refFrameDesc = {};
248 refFrameDesc.pReconstructedPicture = recAlloc.pReconstructedPicture;
249 refFrameDesc.ReconstructedPictureSubresource = recAlloc.ReconstructedPictureSubresource;
250 refFrameDesc.pVideoHeap = nullptr; // D3D12 Video Encode does not need the D3D12VideoEncoderHeap struct for H264
251 // (used for no-key-frame resolution change in VC1, AV1, etc)
252 m_rDPBStorageManager.insert_reference_frame(refFrameDesc, 0);
253
254 // Prepare D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 for added DPB member
255 D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 newDPBDescriptor = {
256 // uint32_t ReconstructedPictureResourceIndex;
257 0, // the associated reconstructed picture is also being pushed_front in m_rDPBStorageManager
258 // BOOL IsLongTermReference;
259 false,
260 // uint32_t LongTermPictureIdx;
261 0,
262 // uint32_t PictureOrderCountNumber;
263 m_curFrameState.PictureOrderCountNumber,
264 // uint32_t FrameDecodingOrderNumber;
265 m_curFrameState.FrameDecodingOrderNumber,
266 // uint32_t TemporalLayerIndex;
267 0 // NO B-hierarchy in this impl of the picture manager
268 };
269
270 // Add DPB entry
271 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.insert(
272 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
273 newDPBDescriptor);
274
275 // Update the indices for ReconstructedPictureResourceIndex in pReferenceFramesReconPictureDescriptors
276 // to be in identity mapping with m_rDPBStorageManager indices
277 // after pushing the elements to the right in the push_front operation
278 for (uint32_t dpbResIdx = 1;
279 dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
280 dpbResIdx++) {
281 auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
282 dpbDesc.ReconstructedPictureResourceIndex = dpbResIdx;
283 }
284 }
285
286 // Number of allocations, disregarding if they are used or not, should not exceed this limit due to reuse policies on
287 // DPB items removal.
288 assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <= (m_MaxDPBCapacity + 1));
289 }
290
291 void
print_l0_l1_lists()292 d3d12_video_encoder_references_manager_h264::print_l0_l1_lists()
293 {
294 if ((D3D12_DEBUG_VERBOSE & d3d12_debug) &&
295 ((m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) ||
296 (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME))) {
297 std::string list0ContentsString;
298 for (uint32_t idx = 0; idx < m_curFrameState.List0ReferenceFramesCount; idx++) {
299 uint32_t value = m_curFrameState.pList0ReferenceFrames[idx];
300 list0ContentsString += "{ DPBidx: ";
301 list0ContentsString += std::to_string(value);
302 list0ContentsString += " - POC: ";
303 list0ContentsString += std::to_string(
304 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].PictureOrderCountNumber);
305 list0ContentsString += " - FrameDecodingOrderNumber: ";
306 list0ContentsString += std::to_string(
307 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].FrameDecodingOrderNumber);
308 list0ContentsString += "}\n";
309 }
310
311 debug_printf(
312 "[D3D12 Video Encoder Picture Manager H264] L0 list for frame with POC %d - frame_num (%d) is: \n %s \n",
313 m_curFrameState.PictureOrderCountNumber,
314 m_curFrameState.FrameDecodingOrderNumber,
315 list0ContentsString.c_str());
316
317 std::string list1ContentsString;
318 for (uint32_t idx = 0; idx < m_curFrameState.List1ReferenceFramesCount; idx++) {
319 uint32_t value = m_curFrameState.pList1ReferenceFrames[idx];
320 list1ContentsString += "{ DPBidx: ";
321 list1ContentsString += std::to_string(value);
322 list1ContentsString += " - POC: ";
323 list1ContentsString += std::to_string(
324 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].PictureOrderCountNumber);
325 list1ContentsString += " - FrameDecodingOrderNumber: ";
326 list1ContentsString += std::to_string(
327 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].FrameDecodingOrderNumber);
328 list1ContentsString += "}\n";
329 }
330
331 debug_printf(
332 "[D3D12 Video Encoder Picture Manager H264] L1 list for frame with POC %d - frame_num (%d) is: \n %s \n",
333 m_curFrameState.PictureOrderCountNumber,
334 m_curFrameState.FrameDecodingOrderNumber,
335 list1ContentsString.c_str());
336 }
337 }
338
339 void
print_dpb()340 d3d12_video_encoder_references_manager_h264::print_dpb()
341 {
342 if (D3D12_DEBUG_VERBOSE & d3d12_debug) {
343 std::string dpbContents;
344 for (uint32_t dpbResIdx = 0;
345 dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
346 dpbResIdx++) {
347 auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
348 auto dpbEntry = m_rDPBStorageManager.get_reference_frame(dpbDesc.ReconstructedPictureResourceIndex);
349
350 dpbContents += "{ DPBidx: ";
351 dpbContents += std::to_string(dpbResIdx);
352 dpbContents += " - POC: ";
353 dpbContents += std::to_string(dpbDesc.PictureOrderCountNumber);
354 dpbContents += " - FrameDecodingOrderNumber: ";
355 dpbContents += std::to_string(dpbDesc.FrameDecodingOrderNumber);
356 dpbContents += " - DPBStorageIdx: ";
357 dpbContents += std::to_string(dpbDesc.ReconstructedPictureResourceIndex);
358 dpbContents += " - DPBStorageResourcePtr: ";
359 char strBuf[256];
360 memset(&strBuf, '\0', 256);
361 sprintf(strBuf, "%p", dpbEntry.pReconstructedPicture);
362 dpbContents += std::string(strBuf);
363 dpbContents += " - DPBStorageSubresource: ";
364 dpbContents += std::to_string(dpbEntry.ReconstructedPictureSubresource);
365 dpbContents += "}\n";
366 }
367
368 debug_printf("[D3D12 Video Encoder Picture Manager H264] DPB has %d frames - DPB references for frame with POC "
369 "%d (frame_num: %d) are: \n %s \n",
370 m_rDPBStorageManager.get_number_of_pics_in_dpb(),
371 m_curFrameState.PictureOrderCountNumber,
372 m_curFrameState.FrameDecodingOrderNumber,
373 dpbContents.c_str());
374 }
375 }
376
377 // Advances state to next frame in GOP; subsequent calls to GetCurrentFrame* point to the advanced frame status
378 void
end_frame()379 d3d12_video_encoder_references_manager_h264::end_frame()
380 {
381 debug_printf("[D3D12 Video Encoder Picture Manager H264] %d resources IN USE out of a total of %d ALLOCATED "
382 "resources at end_frame for frame with POC: %d\n",
383 m_rDPBStorageManager.get_number_of_in_use_allocations(),
384 m_rDPBStorageManager.get_number_of_tracked_allocations(),
385 m_curFrameState.PictureOrderCountNumber);
386
387 // Adds last used (if not null) get_current_frame_recon_pic_output_allocation to DPB for next EncodeFrame if
388 // necessary updates pReferenceFramesReconPictureDescriptors and updates the dpb storage
389
390 update_fifo_dpb_push_front_cur_recon_pic();
391 }
392
393 bool
is_current_frame_used_as_reference()394 d3d12_video_encoder_references_manager_h264::is_current_frame_used_as_reference()
395 {
396 return m_isCurrentFrameUsedAsReference;
397 }
398
399 void
begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,bool bUsedAsReference)400 d3d12_video_encoder_references_manager_h264::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
401 bool bUsedAsReference)
402 {
403 m_curFrameState = *curFrameData.pH264PicData;
404 m_isCurrentFrameUsedAsReference = bUsedAsReference;
405 debug_printf("Marking frame_num %d (POC %d) as reference ? %d\n",
406 curFrameData.pH264PicData->FrameDecodingOrderNumber,
407 curFrameData.pH264PicData->PictureOrderCountNumber,
408 bUsedAsReference);
409
410 // Advance the GOP tracking state
411 bool isDPBFlushNeeded = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME);
412 if (isDPBFlushNeeded) {
413 reset_gop_tracking_and_dpb();
414 } else {
415 // Get new allocation from DPB storage for reconstructed picture
416 // This is only necessary for the frames that come after an IDR
417 // since in the initial state already has this initialized
418 // and re-initialized by reset_gop_tracking_and_dpb above
419
420 prepare_current_frame_recon_pic_allocation();
421 }
422 }
423