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