1 /* 2 * Copyright (c) 2019-2023, 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 decode_av1_tile_coding.cpp 24 //! \brief Defines the common interface for av1 decode tile coding 25 //! 26 27 #include "decode_av1_tile_coding.h" 28 #include "decode_av1_basic_feature.h" 29 #include "codec_def_common.h" 30 #include "decode_pipeline.h" 31 32 namespace decode 33 { ~Av1DecodeTile()34 Av1DecodeTile::~Av1DecodeTile() 35 { 36 // tile descriptors 37 if (m_tileDesc) 38 { 39 free(m_tileDesc); 40 m_tileDesc = nullptr; 41 } 42 } 43 Init(Av1BasicFeature * basicFeature,CodechalSetting * codecSettings)44 MOS_STATUS Av1DecodeTile::Init(Av1BasicFeature *basicFeature, CodechalSetting *codecSettings) 45 { 46 DECODE_FUNC_CALL(); 47 DECODE_CHK_NULL(basicFeature); 48 DECODE_CHK_NULL(codecSettings); 49 50 m_basicFeature = basicFeature; 51 52 return MOS_STATUS_SUCCESS; 53 } 54 Update(CodecAv1PicParams & picParams,CodecAv1TileParams * tileParams)55 MOS_STATUS Av1DecodeTile::Update(CodecAv1PicParams & picParams, 56 CodecAv1TileParams *tileParams) 57 { 58 DECODE_FUNC_CALL(); 59 60 // Initialize state params for multiple tiles 61 if (m_newFrameStart) 62 { 63 m_lastTileId = -1; 64 m_curTile = -1; 65 m_tileStartOffset = 0; 66 m_firstTileInTg = 0; 67 m_tileGroupId = -1; 68 m_isTruncatedTile = false; 69 m_decPassNum = 1; 70 m_hasTileMissing = false; 71 m_hasDuplicateTile = false; 72 } 73 74 if (m_numTiles > av1MaxTileNum) 75 { 76 DECODE_ASSERTMESSAGE("Tile number exceeds the max supported number %d!", av1MaxTileNum); 77 return MOS_STATUS_INVALID_PARAMETER; 78 } 79 80 if (picParams.m_tileCols > av1MaxTileColumn || picParams.m_tileRows > av1MaxTileRow) 81 { 82 DECODE_NORMALMESSAGE("Invalid tile row/col."); 83 return MOS_STATUS_INVALID_PARAMETER; 84 } 85 86 uint16_t tileNumLimit = (picParams.m_picInfoFlags.m_fields.m_largeScaleTile) ? av1MaxTileNum : (picParams.m_tileCols * picParams.m_tileRows); 87 if (nullptr != m_tileDesc) 88 { 89 if (m_prevFrmTileNum < tileNumLimit) 90 { 91 free(m_tileDesc); 92 m_tileDesc = nullptr; 93 } 94 else 95 { 96 memset(m_tileDesc, 0, (sizeof(TileDesc) * m_prevFrmTileNum)); 97 } 98 } 99 if (nullptr == m_tileDesc) 100 { 101 m_tileDesc = (TileDesc *)malloc(sizeof(TileDesc) * tileNumLimit); 102 if (nullptr != m_tileDesc) 103 { 104 memset(m_tileDesc, 0, (sizeof(TileDesc) * tileNumLimit)); 105 } 106 } 107 m_prevFrmTileNum = tileNumLimit; 108 109 //Calculate tile info for max tile 110 DECODE_CHK_STATUS(CalcTileInfoMaxTile(picParams)); 111 112 return MOS_STATUS_SUCCESS; 113 } 114 ErrorDetectAndConceal()115 MOS_STATUS Av1DecodeTile::ErrorDetectAndConceal() 116 { 117 DECODE_FUNC_CALL() 118 DECODE_CHK_NULL(m_tileDesc); 119 uint64_t datasize = 0; 120 121 // detect if any tile missing 122 if (m_numTiles < m_totalTileNum) 123 { 124 if (!m_hasTileMissing) 125 { 126 m_hasTileMissing = true; 127 } 128 } 129 130 // make sure the last tile equals to m_totalTileNum-1 131 if (m_hasTileMissing) 132 { 133 if (m_lastTileId != m_totalTileNum - 1) 134 { 135 m_lastTileId = m_totalTileNum - 1; 136 m_newFrameStart = true; 137 } 138 } 139 140 // Error Concealment for Tile size 141 // m_numTiles means the tile number from application 142 // m_totalTileNum means the total number of tile, m_lastTileId means the last tile index 143 for (uint32_t i = 0; i < m_totalTileNum; i++) 144 { 145 // m_tileDesc[i].m_size + m_tileDesc[i].m_offset could oversize the maximum of uint32_t 146 datasize = (uint64_t)m_tileDesc[i].m_size + (uint64_t)m_tileDesc[i].m_offset; 147 if (datasize > m_basicFeature->m_dataSize) 148 { 149 if (i == m_lastTileId) 150 { 151 if (m_basicFeature->m_dataSize > m_tileDesc[i].m_offset) 152 { 153 m_tileDesc[i].m_size = m_basicFeature->m_dataSize - m_tileDesc[i].m_offset; 154 DECODE_ASSERTMESSAGE("The last tile size is oversize, the remaining size is %d\n", m_tileDesc[i].m_size); 155 } 156 else 157 { 158 m_tileDesc[i].m_size = 0; 159 DECODE_ASSERTMESSAGE("The last tile size is invalid, take current tile as missing tile and then set 4 byte dummy WL!!"); 160 } 161 } 162 else 163 { 164 m_tileDesc[i].m_size = 0; 165 DECODE_ASSERTMESSAGE("The non-last tile size is oversize, take current tile as missing tile and then set 4 byte dummy WL!\n"); 166 } 167 } 168 // For tile missing scenario 169 if (m_tileDesc[i].m_size == 0) 170 { 171 DECODE_ASSERTMESSAGE("The %d tile is missing, set 4 byte dummy WL!\n", i); 172 m_tileDesc[i].m_size = 4; 173 m_tileDesc[i].m_offset = 0; 174 m_tileDesc[i].m_tileRow = i / m_basicFeature->m_av1PicParams->m_tileCols; 175 m_tileDesc[i].m_tileColumn = i % m_basicFeature->m_av1PicParams->m_tileCols; 176 } 177 } 178 return MOS_STATUS_SUCCESS; 179 } 180 ParseTileInfo(const CodecAv1PicParams & picParams,CodecAv1TileParams * tileParams)181 MOS_STATUS Av1DecodeTile::ParseTileInfo(const CodecAv1PicParams & picParams, CodecAv1TileParams *tileParams) 182 { 183 DECODE_FUNC_CALL(); 184 185 DECODE_CHK_NULL(m_tileDesc); 186 m_totalTileNum = (picParams.m_picInfoFlags.m_fields.m_largeScaleTile) ? 187 (picParams.m_tileCountMinus1 + 1) : picParams.m_tileRows * picParams.m_tileCols; 188 189 int16_t tileId = 0; 190 int16_t tileGroupId = -1; 191 int16_t lastStartTileIdx = -1; 192 for (uint32_t i = 0; i < m_numTiles; i++) 193 { 194 DECODE_ASSERT(tileParams[i].m_badBSBufferChopping == 0);//this is to assume the whole tile is in one single bitstream buffer 195 DECODE_ASSERT(tileParams[i].m_bsTileBytesInBuffer == tileParams[i].m_bsTilePayloadSizeInBytes);//this is to assume the whole tile is in one single bitstream buffer 196 197 // Check invalid tile column and tile row 198 if (tileParams[i].m_tileColumn > picParams.m_tileCols || tileParams[i].m_tileRow > picParams.m_tileRows) 199 { 200 DECODE_ASSERTMESSAGE("Invalid tile column or tile row\n"); 201 return MOS_STATUS_INVALID_PARAMETER; 202 } 203 204 if (!picParams.m_picInfoFlags.m_fields.m_largeScaleTile) 205 { 206 //record info 207 if (tileParams[i].m_startTileIdx != lastStartTileIdx) 208 { 209 tileGroupId++; 210 } 211 lastStartTileIdx = tileParams[i].m_startTileIdx; 212 tileId = tileParams[i].m_tileColumn + tileParams[i].m_tileRow * picParams.m_tileCols; 213 if (tileParams[i].m_badBSBufferChopping == 0 || tileParams[i].m_badBSBufferChopping == 2)//if all tile data received 214 { 215 m_lastTileId = tileId;//record the last tile ID whose bitstream is available for HW to decode 216 } 217 } 218 219 // check duplicate tile 220 auto index = (picParams.m_picInfoFlags.m_fields.m_largeScaleTile) ? i : tileId; 221 if (m_tileDesc[index].m_tileIndexCount > 0 ) 222 { 223 if (tileParams[i].m_bsTileBytesInBuffer > m_tileDesc[index].m_size) 224 { 225 m_tileDesc[index].m_offset = tileParams[i].m_bsTileDataLocation; 226 m_tileDesc[index].m_size = tileParams[i].m_bsTileBytesInBuffer; 227 } 228 m_tileDesc[index].m_tileIndexCount++; 229 m_hasDuplicateTile = true; 230 } 231 else 232 { 233 m_tileDesc[index].m_offset = tileParams[i].m_bsTileDataLocation; 234 m_tileDesc[index].m_size = tileParams[i].m_bsTileBytesInBuffer; 235 m_tileDesc[index].m_tileRow = tileParams[i].m_tileRow; 236 m_tileDesc[index].m_tileColumn = tileParams[i].m_tileColumn; 237 m_tileDesc[index].m_tileIndexCount++; 238 } 239 240 if (!picParams.m_picInfoFlags.m_fields.m_largeScaleTile) 241 { 242 m_tileDesc[index].m_tileGroupId = (uint16_t)tileGroupId; 243 m_tileDesc[index].m_lastInGroup = (tileId == tileParams[i].m_endTileIdx) ? true : false; 244 m_tileDesc[index].m_tileNum = tileId - tileParams[i].m_startTileIdx; 245 } 246 else 247 { 248 //No TG for ext-tile, set TG related params to 0 249 m_tileDesc[index].m_tileGroupId = 0; 250 m_tileDesc[index].m_lastInGroup = 0; 251 m_tileDesc[index].m_tileNum = 0; 252 253 //ext-tile specific params 254 m_tileDesc[index].m_tileIndex = tileParams[i].m_tileIndex; 255 m_tileDesc[index].m_anchorFrameIdx = tileParams[i].m_anchorFrameIdx.FrameIdx; 256 } 257 } 258 259 if ((m_lastTileId + 1) == m_totalTileNum) 260 { 261 m_newFrameStart = true; 262 } 263 else 264 { 265 m_newFrameStart = false; 266 } 267 268 // Do error detection and concealment 269 DECODE_CHK_STATUS(ErrorDetectAndConceal()); 270 271 return MOS_STATUS_SUCCESS; 272 } 273 CalculateTileCols(CodecAv1PicParams & picParams)274 MOS_STATUS Av1DecodeTile::CalculateTileCols(CodecAv1PicParams & picParams) 275 { 276 DECODE_FUNC_CALL(); 277 278 int32_t mibSizeLog2 = picParams.m_seqInfoFlags.m_fields.m_use128x128Superblock ? av1MaxMibSizeLog2 : av1MinMibSizeLog2; 279 int32_t miCols = MOS_ALIGN_CEIL(m_miCols, 1 << mibSizeLog2); 280 int32_t sbCols = miCols >> mibSizeLog2; 281 282 //calc tile col start for all the tiles except the last one 283 uint16_t i, start_sb = 0; 284 for (i = 0, start_sb = 0; i < picParams.m_tileCols - 1; i++) 285 { 286 m_tileColStartSb[i] = start_sb;//calc tile col start 287 start_sb += picParams.m_widthInSbsMinus1[i] + 1; 288 } 289 290 //calc for the last tile 291 m_tileColStartSb[i] = start_sb; 292 DECODE_CHK_COND(sbCols < (start_sb + 1), "Invalid tile col start of the last tile"); 293 picParams.m_widthInSbsMinus1[i] = sbCols - start_sb - 1; 294 295 return MOS_STATUS_SUCCESS; 296 } 297 CalculateTileRows(CodecAv1PicParams & picParams)298 MOS_STATUS Av1DecodeTile::CalculateTileRows(CodecAv1PicParams &picParams) 299 { 300 DECODE_FUNC_CALL(); 301 302 int32_t mibSizeLog2 = picParams.m_seqInfoFlags.m_fields.m_use128x128Superblock ? av1MaxMibSizeLog2 : av1MinMibSizeLog2; 303 int32_t miRows = MOS_ALIGN_CEIL(m_miRows, 1 << mibSizeLog2); 304 int32_t sbRows = miRows >> mibSizeLog2; 305 306 //calc tile row start for all the tiles except the last one 307 uint16_t i, start_sb; 308 for (i = 0, start_sb = 0; i < picParams.m_tileRows - 1; i++) 309 { 310 m_tileRowStartSb[i] = start_sb;//calc tile Row start 311 start_sb += picParams.m_heightInSbsMinus1[i] + 1; 312 } 313 314 //calc for the last tile 315 m_tileRowStartSb[i] = start_sb; 316 DECODE_CHK_COND(sbRows < (start_sb + 1), "Invalid tile row start of the last tile"); 317 picParams.m_heightInSbsMinus1[i] = sbRows - start_sb - 1; 318 319 return MOS_STATUS_SUCCESS; 320 } 321 CalcTileInfoMaxTile(CodecAv1PicParams & picParams)322 MOS_STATUS Av1DecodeTile::CalcTileInfoMaxTile(CodecAv1PicParams &picParams) 323 { 324 DECODE_FUNC_CALL(); 325 326 m_miCols = MOS_ALIGN_CEIL(picParams.m_frameWidthMinus1 + 1, 8) >> av1MiSizeLog2; 327 m_miRows = MOS_ALIGN_CEIL(picParams.m_frameHeightMinus1 + 1, 8) >> av1MiSizeLog2; 328 DECODE_CHK_STATUS(CalculateTileCols(picParams)); 329 DECODE_CHK_STATUS(CalculateTileRows(picParams)); 330 331 return MOS_STATUS_SUCCESS; 332 } 333 CalcNumPass(const CodecAv1PicParams & picParams,CodecAv1TileParams * tileParams)334 MOS_STATUS Av1DecodeTile::CalcNumPass(const CodecAv1PicParams &picParams, CodecAv1TileParams *tileParams) 335 { 336 DECODE_FUNC_CALL(); 337 338 uint16_t passNum; 339 uint16_t startTile = m_lastTileId + 1;//record before parsing new bitstream portion 340 341 DECODE_CHK_STATUS(ParseTileInfo(picParams, tileParams)); 342 343 if (picParams.m_picInfoFlags.m_fields.m_largeScaleTile) 344 { 345 passNum = picParams.m_tileCountMinus1 + 1; 346 m_curTile = 0; 347 } 348 else 349 { 350 passNum = m_lastTileId - startTile + 1; 351 m_curTile = startTile; 352 } 353 354 m_decPassNum = passNum; 355 return MOS_STATUS_SUCCESS; 356 } 357 GetUpscaleConvolveStepX0(const CodecAv1PicParams & picParams,bool isChroma)358 void Av1DecodeTile::GetUpscaleConvolveStepX0(const CodecAv1PicParams &picParams, bool isChroma) 359 { 360 DECODE_FUNC_CALL(); 361 362 int32_t ssX = isChroma && picParams.m_seqInfoFlags.m_fields.m_subsamplingX; 363 int32_t downscaledPlaneWidth = ROUND_POWER_OF_TWO(picParams.m_frameWidthMinus1 + 1, ssX); 364 int32_t upscaledPlaneWidth = ROUND_POWER_OF_TWO(picParams.m_superResUpscaledWidthMinus1 + 1, ssX); 365 366 //calculate step 367 int32_t xStepQn = ((downscaledPlaneWidth << av1RsScaleSubpelBits) + upscaledPlaneWidth / 2) / upscaledPlaneWidth; 368 if (isChroma) 369 { 370 m_chromaXStepQn = xStepQn; 371 } 372 else 373 { 374 m_lumaXStepQn = xStepQn; 375 } 376 377 //Calculate x0_qn for each tile column 378 int32_t err = upscaledPlaneWidth * xStepQn - (downscaledPlaneWidth << av1RsScaleSubpelBits); 379 int32_t x0 = 380 (-((upscaledPlaneWidth - downscaledPlaneWidth) << (av1RsScaleSubpelBits - 1)) + 381 upscaledPlaneWidth / 2) / 382 upscaledPlaneWidth + 383 av1RsScaleExtraOff - err / 2; 384 x0 = (int32_t)((uint32_t)x0 & av1RsScaleSubpelMask); 385 386 if (picParams.m_tileCols > 64) 387 { 388 DECODE_ASSERTMESSAGE("Array index exceeds upper bound."); 389 return; 390 } 391 392 for (auto col = 0; col < picParams.m_tileCols; col++) 393 { 394 if (isChroma) 395 { 396 m_chromaX0Qn[col] = x0; 397 } 398 else 399 { 400 m_lumaX0Qn[col] = x0; 401 } 402 403 int32_t tileColEndSb; 404 if (col < picParams.m_tileCols - 1) 405 { 406 tileColEndSb = m_tileColStartSb[col + 1]; 407 } 408 else 409 { 410 tileColEndSb = m_tileColStartSb[picParams.m_tileCols - 1] + picParams.m_widthInSbsMinus1[picParams.m_tileCols - 1]; 411 412 } 413 int32_t mibSizeLog2 = picParams.m_seqInfoFlags.m_fields.m_use128x128Superblock ? av1MaxMibSizeLog2 : av1MinMibSizeLog2; 414 415 int32_t miColEnd = tileColEndSb << mibSizeLog2; 416 miColEnd = AOMMIN(miColEnd, m_miCols); 417 int32_t downscaledX1 = miColEnd << (av1MiSizeLog2 - ssX); 418 int32_t downscaledX0 = m_tileColStartSb[col] << mibSizeLog2 << (av1MiSizeLog2 - ssX); 419 420 int32_t srcWidth = downscaledX1 - downscaledX0; 421 int32_t upscaledX0 = (downscaledX0 * picParams.m_superresScaleDenominator) / av1ScaleNumerator; 422 int32_t upscaledX1; 423 if (col == picParams.m_tileCols - 1) 424 { 425 upscaledX1 = upscaledPlaneWidth; 426 } 427 else 428 { 429 upscaledX1 = (downscaledX1 * picParams.m_superresScaleDenominator) / av1ScaleNumerator; 430 } 431 int32_t dstWidth = upscaledX1 - upscaledX0; 432 433 // Update the fractional pixel offset to prepare for the next tile column. 434 x0 += (dstWidth * xStepQn) - (srcWidth << av1RsScaleSubpelBits); 435 } 436 } 437 438 } // namespace decode 439