1 /*
2 * Copyright (c) 2018-2020, Intel 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 shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file     encode_hevc_vdenc_roi.h
24 //! \brief    implementation of ROI feature of HEVC VDENC
25 
26 #include "mos_defs.h"
27 #include "encode_hevc_basic_feature.h"
28 #include "encode_hevc_vdenc_roi_overlap.h"
29 #include "encode_hevc_vdenc_roi_strategy.h"
30 #include "encode_hevc_vdenc_roi_native.h"
31 #include "encode_hevc_vdenc_roi_huc_forceqp.h"
32 #include "encode_hevc_vdenc_roi_forceqp.h"
33 #include "encode_hevc_vdenc_roi_dirty.h"
34 #include "encode_hevc_vdenc_roi_qpmap.h"
35 #include "encode_hevc_vdenc_roi_arb.h"
36 #include "encode_hevc_vdenc_roi_forcedeltaqp.h"
37 #include "encode_hevc_brc.h"
38 #include "encode_hevc_tile.h"
39 
40 namespace encode
41 {
PrepareParams(SeqParams * hevcSeqParams,PicParams * hevcPicParams,SlcParams * hevcSlcParams)42 MOS_STATUS RoiStrategy::PrepareParams(
43     SeqParams *hevcSeqParams,
44     PicParams *hevcPicParams,
45     SlcParams *hevcSlcParams)
46 {
47     ENCODE_CHK_NULL_RETURN(hevcSeqParams);
48     ENCODE_CHK_NULL_RETURN(hevcPicParams);
49     ENCODE_CHK_NULL_RETURN(hevcSlcParams);
50 
51     m_numRoi     = hevcPicParams->NumROI;
52     m_roiRegions = hevcPicParams->ROI;
53     ENCODE_CHK_NULL_RETURN(m_roiRegions);
54 
55     m_targetUsage = hevcSeqParams->TargetUsage;
56 
57     m_qpY          = hevcPicParams->QpY;
58     m_sliceQpDelta = hevcSlcParams->slice_qp_delta;
59 
60     m_isTileModeEnabled  = hevcPicParams->tiles_enabled_flag;
61     m_minCodingBlockSize = hevcSeqParams->log2_min_coding_block_size_minus3 + 3;
62 
63     m_numDistinctDeltaQp = sizeof(hevcPicParams->ROIDistinctDeltaQp) / sizeof(int8_t);
64     m_roiDistinctDeltaQp = hevcPicParams->ROIDistinctDeltaQp;
65     ENCODE_CHK_NULL_RETURN(m_roiDistinctDeltaQp);
66 
67     return MOS_STATUS_SUCCESS;
68 }
69 
StreaminZigZagToLinearMap(uint32_t streamInWidth,uint32_t x,uint32_t y,uint32_t * offset,uint32_t * xyOffset)70 void RoiStrategy::StreaminZigZagToLinearMap(
71     uint32_t  streamInWidth,
72     uint32_t  x,
73     uint32_t  y,
74     uint32_t *offset,
75     uint32_t *xyOffset)
76 {
77     ENCODE_FUNC_CALL();
78 
79     *offset          = streamInWidth * y;
80     uint32_t yOffset = 0;
81     uint32_t xOffset = 2 * x;
82 
83     //Calculate X Y Offset for the zig zag scan with in each 64x64 LCU
84     //dwOffset gives the 64 LCU row
85     if (y % 2)
86     {
87         *offset = streamInWidth * (y - 1);
88         yOffset = 2;
89     }
90 
91     if (x % 2)
92     {
93         xOffset = (2 * x) - 1;
94     }
95 
96     *xyOffset = xOffset + yOffset;
97 }
98 
ZigZagToRaster(uint32_t streamInWidth,uint32_t lcuIndex,uint32_t & x,uint32_t & y)99 void RoiStrategy::ZigZagToRaster(
100     uint32_t streamInWidth,
101     uint32_t lcuIndex,
102     uint32_t &x,
103     uint32_t &y)
104 {
105     ENCODE_FUNC_CALL();
106 
107     uint32_t lcu64Index  = lcuIndex / 4;
108     uint32_t OffsetInlcu64 = lcuIndex % 4;
109     uint32_t XoffsetIn64 = lcu64Index % (streamInWidth / 2);
110     x = XoffsetIn64 * 2 + OffsetInlcu64 % 2;
111     uint32_t YoffsetIn64 = lcu64Index / (streamInWidth / 2);
112     y = YoffsetIn64 * 2 + OffsetInlcu64 / 2;
113 }
114 
SetStreaminDataPerRegion(const UintVector & lcuVector,StreamInParams * streaminParams,void * streaminData)115 void RoiStrategy::SetStreaminDataPerRegion(
116     const UintVector &lcuVector,
117     StreamInParams *streaminParams,
118     void *streaminData)
119 {
120     ENCODE_FUNC_CALL();
121 
122     uint8_t *data = (uint8_t *)streaminData;
123 
124     for (uint32_t lcu : lcuVector)
125     {
126         SetStreaminDataPerLcu(streaminParams, data + lcu * 64);
127     }
128 }
129 
SetStreaminDataPerLcu(StreamInParams * streaminParams,void * streaminData)130 void RoiStrategy::SetStreaminDataPerLcu(
131     StreamInParams *streaminParams,
132     void *          streaminData)
133 {
134     ENCODE_FUNC_CALL();
135     HevcVdencStreamInState *data = (HevcVdencStreamInState *)streaminData;
136 
137     data->DW0.MaxTuSize                = streaminParams->maxTuSize;
138     data->DW0.MaxCuSize                = streaminParams->maxCuSize;
139     data->DW0.NumImePredictors         = streaminParams->numImePredictors;
140     data->DW0.PuTypeCtrl               = streaminParams->puTypeCtrl;
141     data->DW6.NumMergeCandidateCu64x64 = streaminParams->numMergeCandidateCu64x64;
142     data->DW6.NumMergeCandidateCu32x32 = streaminParams->numMergeCandidateCu32x32;
143     data->DW6.NumMergeCandidateCu16x16 = streaminParams->numMergeCandidateCu16x16;
144     data->DW6.NumMergeCandidateCu8x8   = streaminParams->numMergeCandidateCu8x8;
145 }
146 
SetupRoi(RoiOverlap & overlap)147 MOS_STATUS RoiStrategy::SetupRoi(RoiOverlap &overlap)
148 {
149     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
150 
151     ENCODE_FUNC_CALL();
152 
153     ENCODE_CHK_NULL_RETURN(m_allocator);
154     ENCODE_CHK_NULL_RETURN(m_basicFeature);
155 
156     uint32_t streamInWidth  = (MOS_ALIGN_CEIL(m_basicFeature->m_frameWidth, 64) / 32);
157     uint32_t streamInHeight = (MOS_ALIGN_CEIL(m_basicFeature->m_frameHeight, 64) / 32) + 8;
158     int32_t  streamInNumCUs = streamInWidth * streamInHeight;
159 
160     //ROI higher priority for smaller index.
161     bool cu64Align = true;
162 
163     for (int32_t i = m_numRoi - 1; i >= 0; i--)
164     {
165         //Check if the region is with in the borders
166         uint16_t top    = (uint16_t)
167             CodecHal_Clip3(0, (streamInHeight - 1), m_roiRegions[i].Top);
168         uint16_t bottom = (uint16_t)
169             CodecHal_Clip3(0, streamInHeight, m_roiRegions[i].Bottom);
170         uint16_t left   = (uint16_t)
171             CodecHal_Clip3(0, (streamInWidth - 1), m_roiRegions[i].Left);
172         uint16_t right  = (uint16_t)
173             CodecHal_Clip3(0, streamInWidth, m_roiRegions[i].Right);
174 
175         //Check if all the sides of ROI regions are aligned to 64CU
176         if ((top % 2 == 1) ||
177             (bottom % 2 == 1) ||
178             (left % 2 == 1) ||
179             (right % 2 == 1))
180         {
181             cu64Align = false;
182             break;
183         }
184     }
185 
186     for (int32_t i = m_numRoi - 1; i >= 0; i--)
187     {
188         //Check if the region is with in the borders
189         uint16_t top    = (uint16_t)
190             CodecHal_Clip3(0, (streamInHeight - 1), m_roiRegions[i].Top);
191         uint16_t bottom = (uint16_t)
192             CodecHal_Clip3(0, streamInHeight, m_roiRegions[i].Bottom);
193         uint16_t left   = (uint16_t)
194             CodecHal_Clip3(0, (streamInWidth - 1), m_roiRegions[i].Left);
195         uint16_t right  = (uint16_t)
196             CodecHal_Clip3(0, streamInWidth, m_roiRegions[i].Right);
197 
198         UintVector lcuVector;
199         GetLCUsInRoiRegion(streamInWidth, top, bottom, left, right, lcuVector);
200 
201         overlap.MarkLcus(lcuVector, cu64Align ?
202             RoiOverlap::mkRoi : RoiOverlap::mkRoiNone64Align, i);
203     }
204 
205     for (auto i = 0; i < streamInNumCUs; i++)
206     {
207         overlap.MarkLcu(i, cu64Align ?
208             RoiOverlap::mkRoiBk : RoiOverlap::mkRoiBkNone64Align);
209     }
210 
211     return eStatus;
212 }
213 
WriteStreaminData(uint32_t lcuIndex,RoiOverlap::OverlapMarker marker,uint32_t roiRegionIndex,uint8_t * rawStreamIn)214 MOS_STATUS RoiStrategy::WriteStreaminData(
215     uint32_t lcuIndex,
216     RoiOverlap::OverlapMarker marker,
217     uint32_t roiRegionIndex,
218     uint8_t *rawStreamIn)
219 {
220     ENCODE_CHK_NULL_RETURN(rawStreamIn);
221 
222     StreamInParams streaminDataParams = {};
223 
224     bool cu64Align = true;
225 
226     switch (marker)
227     {
228     case RoiOverlap::mkRoi:
229         cu64Align                       = true;
230         streaminDataParams.setQpRoiCtrl = true;
231         break;
232 
233     case RoiOverlap::mkRoiNone64Align:
234         cu64Align                       = false;
235         streaminDataParams.setQpRoiCtrl = true;
236         break;
237 
238     case RoiOverlap::mkRoiBk:
239         cu64Align = true;
240         break;
241 
242     case RoiOverlap::mkRoiBkNone64Align:
243         cu64Align = false;
244         break;
245 
246     default:
247         return MOS_STATUS_INVALID_PARAMETER;
248     }
249 
250     SetRoiCtrlMode(lcuIndex, roiRegionIndex, streaminDataParams);
251     SetQpRoiCtrlPerLcu(&streaminDataParams, (HevcVdencStreamInState *)(rawStreamIn + (lcuIndex * 64)));
252 
253     MOS_ZeroMemory(&streaminDataParams, sizeof(streaminDataParams));
254     SetStreaminParamByTU(cu64Align, streaminDataParams);
255     SetStreaminDataPerLcu(&streaminDataParams, rawStreamIn + (lcuIndex * 64));
256 
257     return MOS_STATUS_SUCCESS;
258 }
259 
SetStreaminParamByTU(bool cu64Align,StreamInParams & streaminDataParams)260 void RoiStrategy::SetStreaminParamByTU(
261     bool cu64Align,
262     StreamInParams &streaminDataParams)
263 {
264     MOS_ZeroMemory(&streaminDataParams, sizeof(streaminDataParams));
265 
266     auto settings = static_cast<HevcVdencFeatureSettings *>(m_featureManager->GetFeatureSettings()->GetConstSettings());
267     ENCODE_CHK_NULL_NO_STATUS_RETURN(settings);
268 
269     for (const auto &lambda : settings->vdencStreaminStateSettings)
270     {
271         lambda(streaminDataParams, cu64Align);
272     }
273 }
274 
GetLCUsInRoiRegionForTile(uint32_t streamInWidth,uint32_t top,uint32_t bottom,uint32_t left,uint32_t right,UintVector & lcuVector)275 void RoiStrategy::GetLCUsInRoiRegionForTile(
276     uint32_t    streamInWidth,
277     uint32_t    top,
278     uint32_t    bottom,
279     uint32_t    left,
280     uint32_t    right,
281     UintVector &lcuVector)
282 {
283     ENCODE_FUNC_CALL();
284 
285     auto tileFeature = dynamic_cast<HevcEncodeTile *>(m_featureManager->GetFeature(HevcFeatureIDs::encodeTile));
286     ENCODE_CHK_NULL_NO_STATUS_RETURN(tileFeature);
287 
288     uint32_t tileStartLcuX = 0, tileEndLcuX = 0;
289     uint32_t tileStartLcuY = 0, tileEndLcuY = 0;
290     uint32_t streamInBaseOffset = 0;
291 
292     tileFeature->GetTileInfo(left,
293         top,
294         tileStartLcuX,
295         tileEndLcuX,
296         tileStartLcuY,
297         tileEndLcuY,
298         streamInBaseOffset);
299 
300     for (auto y = top; y < bottom; y++)
301     {
302         for (auto x = left; x < right; x++)
303         {
304             if (x < (tileStartLcuX * 2) ||
305                 y < (tileStartLcuY * 2) ||
306                 x >= (tileEndLcuX * 2) ||
307                 y >= (tileEndLcuY * 2))
308             {
309                 tileFeature->GetTileInfo(x,
310                     y,
311                     tileStartLcuX,
312                     tileEndLcuX,
313                     tileStartLcuY,
314                     tileEndLcuY,
315                     streamInBaseOffset);
316             }
317 
318             auto xPositionInTile = x - (tileStartLcuX * 2);
319             auto yPositionInTile = y - (tileStartLcuY * 2);
320             auto tileWidthInLCU  = tileEndLcuX - tileStartLcuX;
321 
322             uint32_t offset = 0, xyOffset = 0;
323 
324             StreaminZigZagToLinearMap(
325                 tileWidthInLCU * 2,
326                 xPositionInTile,
327                 yPositionInTile,
328                 &offset,
329                 &xyOffset);
330 
331             lcuVector.push_back(streamInBaseOffset + offset + xyOffset);
332         }
333     }
334 }
335 
GetLCUsInRoiRegion(uint32_t streamInWidth,uint32_t top,uint32_t bottom,uint32_t left,uint32_t right,UintVector & lcuVector)336 void RoiStrategy::GetLCUsInRoiRegion(
337     uint32_t    streamInWidth,
338     uint32_t    top,
339     uint32_t    bottom,
340     uint32_t    left,
341     uint32_t    right,
342     UintVector &lcuVector)
343 {
344     if (m_isTileModeEnabled)
345     {
346         GetLCUsInRoiRegionForTile(streamInWidth, top, bottom, left, right, lcuVector);
347         return;
348     }
349 
350     for (auto y = top; y < bottom; y++)
351     {
352         for (auto x = left; x < right; x++)
353         {
354             //Calculate X Y for the zig zag scan
355             uint32_t offset = 0, xyOffset = 0;
356             StreaminZigZagToLinearMap(streamInWidth, x, y, &offset, &xyOffset);
357 
358             lcuVector.push_back(offset + xyOffset);
359         }
360     }
361 }
362 
363 /*******************************************************
364 
365     Following is for RoiStrategyFactory
366 
367 *******************************************************/
368 
CreateStrategy(EncodeAllocator * allocator,MediaFeatureManager * featureManager,PMOS_INTERFACE m_osInterface,bool isArb,bool isDirtyRoi,bool isNativeRoi,bool isQPMap)369 RoiStrategy *RoiStrategyFactory::CreateStrategy(
370     EncodeAllocator     *allocator,
371     MediaFeatureManager *featureManager,
372     PMOS_INTERFACE       m_osInterface,
373     bool                 isArb,
374     bool                 isDirtyRoi,
375     bool                 isNativeRoi,
376     bool                 isQPMap)
377 {
378     RoiStrategy *strategy = nullptr;
379 
380     if (isArb)
381     {
382         strategy     = m_arbRoi == nullptr ? m_arbRoi = MOS_New(ArbROI, allocator, featureManager, m_osInterface) : m_arbRoi;
383         m_currentRoi = strategy;
384         return strategy;
385     }
386 
387     if (isDirtyRoi)
388     {
389         strategy   = (m_dirtyRoi == nullptr) ?
390             m_dirtyRoi = MOS_New(DirtyROI, allocator, featureManager, m_osInterface) : m_dirtyRoi;
391 
392         return strategy;
393     }
394 
395     if (isNativeRoi)
396     {
397         strategy     = (m_nativeRoi == nullptr) ?
398             m_nativeRoi = MOS_New(NativeROI, allocator, featureManager, m_osInterface) : m_nativeRoi;
399         m_currentRoi = strategy;
400         return strategy;
401     }
402 
403     if (isQPMap)
404     {
405         strategy = (m_QPMapROI == nullptr) ?
406             m_QPMapROI = MOS_New(QPMapROI, allocator, featureManager, m_osInterface) : m_QPMapROI;
407         m_currentRoi = strategy;
408         return strategy;
409     }
410 
411     auto brcFeature = dynamic_cast<HEVCEncodeBRC *>
412         (featureManager->GetFeature(HevcFeatureIDs::hevcBrcFeature));
413     if (brcFeature != nullptr && brcFeature->IsVdencHucUsed())
414     {
415         strategy = (m_hucForceQpRoi == nullptr) ?
416             m_hucForceQpRoi = MOS_New(HucForceQpROI, allocator, featureManager, m_osInterface) : m_hucForceQpRoi;
417 
418         m_currentRoi = strategy;
419         return strategy;
420     }
421 
422     strategy     = (m_forceQpRoi == nullptr) ?
423         m_forceQpRoi = MOS_New(ForceQPROI, allocator, featureManager, m_osInterface) : m_forceQpRoi;
424 
425     m_currentRoi = strategy;
426     return strategy;
427 }
428 
CreateStrategyForceDeltaQP(EncodeAllocator * allocator,MediaFeatureManager * featureManager,PMOS_INTERFACE m_osInterface)429 RoiStrategy *RoiStrategyFactory::CreateStrategyForceDeltaQP(
430     EncodeAllocator* allocator,
431     MediaFeatureManager* featureManager,
432     PMOS_INTERFACE m_osInterface)
433 {
434     RoiStrategy *strategy = nullptr;
435 
436     strategy = (m_deltaQpRoi == nullptr) ?
437         m_deltaQpRoi = MOS_New(ForceDeltaQPROI, allocator, featureManager, m_osInterface) : m_deltaQpRoi;
438     m_currentRoi = strategy;
439 
440     return strategy;
441 }
442 
~RoiStrategyFactory()443 RoiStrategyFactory::~RoiStrategyFactory()
444 {
445     if (m_dirtyRoi != nullptr)
446     {
447         MOS_Delete(m_dirtyRoi);
448         m_dirtyRoi = nullptr;
449     }
450 
451     if (m_nativeRoi != nullptr)
452     {
453         MOS_Delete(m_nativeRoi);
454         m_nativeRoi = nullptr;
455     }
456 
457     if (m_arbRoi != nullptr)
458     {
459         MOS_Delete(m_arbRoi);
460         m_arbRoi = nullptr;
461     }
462 
463     if (m_deltaQpRoi != nullptr)
464     {
465         MOS_Delete(m_deltaQpRoi);
466         m_deltaQpRoi = nullptr;
467     }
468 
469     if (m_hucForceQpRoi != nullptr)
470     {
471         MOS_Delete(m_hucForceQpRoi);
472         m_hucForceQpRoi = nullptr;
473     }
474 
475     if (m_forceQpRoi != nullptr)
476     {
477         MOS_Delete(m_forceQpRoi);
478         m_forceQpRoi = nullptr;
479     }
480 
481     if (m_QPMapROI != nullptr)
482     {
483         MOS_Delete(m_QPMapROI);
484         m_QPMapROI = nullptr;
485     }
486 }
487 
488 }  // namespace encode
489