• 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_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