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