1 /*!
2 * \copy
3 * Copyright (c) 2009-2013, Cisco Systems
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *
32 * \file fmo.c
33 *
34 * \brief Flexible Macroblock Ordering implementation
35 *
36 * \date 2/4/2009 Created
37 *
38 *************************************************************************************
39 */
40
41 #include "fmo.h"
42 #include "memory_align.h"
43 #include "error_code.h"
44
45 namespace WelsDec {
46
47 /*!
48 * \brief Generate MB allocated map for interleaved slice group (TYPE 0)
49 *
50 * \param pFmo fmo context
51 * \param pPps pps context
52 *
53 * \return 0 - successful; none 0 - failed
54 */
FmoGenerateMbAllocMapType0(PFmo pFmo,PPps pPps)55 static inline int32_t FmoGenerateMbAllocMapType0 (PFmo pFmo, PPps pPps) {
56 uint32_t uiNumSliceGroups = 0;
57 int32_t iMbNum = 0;
58 int32_t i = 0;
59
60 WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pFmo || NULL == pPps))
61 uiNumSliceGroups = pPps->uiNumSliceGroups;
62 iMbNum = pFmo->iCountMbNum;
63 WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pFmo->pMbAllocMap || iMbNum <= 0
64 || uiNumSliceGroups > MAX_SLICEGROUP_IDS))
65
66 do {
67 uint8_t uiGroup = 0;
68 do {
69 const int32_t kiRunIdx = pPps->uiRunLength[uiGroup];
70 int32_t j = 0;
71 do {
72 pFmo->pMbAllocMap[i + j] = uiGroup;
73 ++ j;
74 } while (j < kiRunIdx && i + j < iMbNum);
75 i += kiRunIdx;
76 ++ uiGroup;
77 } while (uiGroup < uiNumSliceGroups && i < iMbNum);
78 } while (i < iMbNum);
79
80 return ERR_NONE; // well here
81 }
82
83 /*!
84 * \brief Generate MB allocated map for dispersed slice group (TYPE 1)
85 *
86 * \param pFmo fmo context
87 * \param pPps pps context
88 * \param iMbWidth MB width
89 *
90 * \return 0 - successful; none 0 - failed
91 */
FmoGenerateMbAllocMapType1(PFmo pFmo,PPps pPps,const int32_t kiMbWidth)92 static inline int32_t FmoGenerateMbAllocMapType1 (PFmo pFmo, PPps pPps, const int32_t kiMbWidth) {
93 uint32_t uiNumSliceGroups = 0;
94 int32_t iMbNum = 0;
95 int32_t i = 0;
96 WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pFmo || NULL == pPps))
97 uiNumSliceGroups = pPps->uiNumSliceGroups;
98 iMbNum = pFmo->iCountMbNum;
99 WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pFmo->pMbAllocMap || iMbNum <= 0 || kiMbWidth == 0
100 || uiNumSliceGroups > MAX_SLICEGROUP_IDS))
101
102 do {
103 pFmo->pMbAllocMap[i] = (uint8_t) (((i % kiMbWidth) + (((i / kiMbWidth) * uiNumSliceGroups) >> 1)) % uiNumSliceGroups);
104 ++ i;
105 } while (i < iMbNum);
106
107 return ERR_NONE; // well here
108 }
109
110 /*!
111 * \brief Generate MB allocated map for various type of slice group cases (TYPE 0, .., 6)
112 *
113 * \param pFmo fmo context
114 * \param pPps pps context
115 * \param kiMbWidth MB width
116 * \param kiMbHeight MB height
117 *
118 * \return 0 - successful; none 0 - failed
119 */
FmoGenerateSliceGroup(PFmo pFmo,const PPps kpPps,const int32_t kiMbWidth,const int32_t kiMbHeight,CMemoryAlign * pMa)120 static inline int32_t FmoGenerateSliceGroup (PFmo pFmo, const PPps kpPps, const int32_t kiMbWidth,
121 const int32_t kiMbHeight, CMemoryAlign* pMa) {
122 int32_t iNumMb = 0;
123 int32_t iErr = 0;
124 bool bResolutionChanged = false;
125
126 // the cases we would not like
127 WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pFmo || NULL == kpPps))
128
129 iNumMb = kiMbWidth * kiMbHeight;
130
131 if (0 == iNumMb)
132 return ERR_INFO_INVALID_PARAM;
133
134 pMa->WelsFree (pFmo->pMbAllocMap, "_fmo->pMbAllocMap");
135 pFmo->pMbAllocMap = (uint8_t*)pMa->WelsMallocz (iNumMb * sizeof (uint8_t), "_fmo->pMbAllocMap");
136 WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, (NULL == pFmo->pMbAllocMap)) // out of memory
137
138 pFmo->iCountMbNum = iNumMb;
139
140 if (kpPps->uiNumSliceGroups < 2 && iNumMb > 0) { // only one slice group, exactly it is single slice based
141 memset (pFmo->pMbAllocMap, 0, iNumMb * sizeof (int8_t)); // for safe
142
143 pFmo->iSliceGroupCount = 1;
144
145 return ERR_NONE;
146 }
147
148 if (bResolutionChanged || ((int32_t)kpPps->uiSliceGroupMapType != pFmo->iSliceGroupType)
149 || ((int32_t)kpPps->uiNumSliceGroups != pFmo->iSliceGroupCount)) {
150 switch (kpPps->uiSliceGroupMapType) {
151 case 0:
152 iErr = FmoGenerateMbAllocMapType0 (pFmo, kpPps);
153 break;
154 case 1:
155 iErr = FmoGenerateMbAllocMapType1 (pFmo, kpPps, kiMbWidth);
156 break;
157 case 2:
158 case 3:
159 case 4:
160 case 5:
161 case 6:
162 // Reserve for others slice group type
163 iErr = 1;
164 break;
165 default:
166 return ERR_INFO_UNSUPPORTED_FMOTYPE;
167 }
168 }
169
170 if (0 == iErr) { // well now
171 pFmo->iSliceGroupCount = kpPps->uiNumSliceGroups;
172 pFmo->iSliceGroupType = kpPps->uiSliceGroupMapType;
173 }
174
175 return iErr;
176 }
177
178 /*!
179 * \brief Initialize Wels Flexible Macroblock Ordering (FMO)
180 *
181 * \param pFmo Wels fmo to be initialized
182 * \param pPps pps argument
183 * \param kiMbWidth mb width
184 * \param kiMbHeight mb height
185 *
186 * \return 0 - successful; none 0 - failed;
187 */
InitFmo(PFmo pFmo,PPps pPps,const int32_t kiMbWidth,const int32_t kiMbHeight,CMemoryAlign * pMa)188 int32_t InitFmo (PFmo pFmo, PPps pPps, const int32_t kiMbWidth, const int32_t kiMbHeight, CMemoryAlign* pMa) {
189 return FmoGenerateSliceGroup (pFmo, pPps, kiMbWidth, kiMbHeight, pMa);
190 }
191
192
193 /*!
194 * \brief Uninitialize Wels Flexible Macroblock Ordering (FMO) list
195 *
196 * \param pFmo Wels base fmo ptr to be uninitialized
197 * \param kiCnt count number of PPS per list
198 * \param kiAvail count available number of PPS in list
199 *
200 * \return NONE
201 */
UninitFmoList(PFmo pFmo,const int32_t kiCnt,const int32_t kiAvail,CMemoryAlign * pMa)202 void UninitFmoList (PFmo pFmo, const int32_t kiCnt, const int32_t kiAvail, CMemoryAlign* pMa) {
203 PFmo pIter = pFmo;
204 int32_t i = 0;
205 int32_t iFreeNodes = 0;
206
207 if (NULL == pIter || kiAvail <= 0 || kiCnt < kiAvail)
208 return;
209
210 while (i < kiCnt) {
211 if (pIter != NULL && pIter->bActiveFlag) {
212 if (NULL != pIter->pMbAllocMap) {
213 pMa->WelsFree (pIter->pMbAllocMap, "pIter->pMbAllocMap");
214
215 pIter->pMbAllocMap = NULL;
216 }
217 pIter->iSliceGroupCount = 0;
218 pIter->iSliceGroupType = -1;
219 pIter->iCountMbNum = 0;
220 pIter->bActiveFlag = false;
221 ++ iFreeNodes;
222 if (iFreeNodes >= kiAvail)
223 break;
224 }
225 ++ pIter;
226 ++ i;
227 }
228 }
229
230 /*!
231 * \brief detect parameter sets are changed or not
232 *
233 * \param pFmo fmo context
234 * \param kiCountNumMb (iMbWidth * iMbHeight) in Sps
235 * \param iSliceGroupType slice group type if fmo is exactly enabled
236 * \param iSliceGroupCount slice group count if fmo is exactly enabled
237 *
238 * \return true - changed or not initialized yet; false - not change at all
239 */
FmoParamSetsChanged(PFmo pFmo,const int32_t kiCountNumMb,const int32_t kiSliceGroupType,const int32_t kiSliceGroupCount)240 bool FmoParamSetsChanged (PFmo pFmo, const int32_t kiCountNumMb, const int32_t kiSliceGroupType,
241 const int32_t kiSliceGroupCount) {
242 WELS_VERIFY_RETURN_IF (false, (NULL == pFmo))
243
244 return ((!pFmo->bActiveFlag)
245 || (kiCountNumMb != pFmo->iCountMbNum)
246 || (kiSliceGroupType != pFmo->iSliceGroupType)
247 || (kiSliceGroupCount != pFmo->iSliceGroupCount));
248 }
249
250 /*!
251 * \brief update/insert FMO parameter unit
252 *
253 * \param _fmo FMO context
254 * \param _sps PSps
255 * \param _pps PPps
256 * \param pActiveFmoNum int32_t* [in/out]
257 *
258 * \return true - update/insert successfully; false - failed;
259 */
FmoParamUpdate(PFmo pFmo,PSps pSps,PPps pPps,int32_t * pActiveFmoNum,CMemoryAlign * pMa)260 int32_t FmoParamUpdate (PFmo pFmo, PSps pSps, PPps pPps, int32_t* pActiveFmoNum, CMemoryAlign* pMa) {
261 const uint32_t kuiMbWidth = pSps->iMbWidth;
262 const uint32_t kuiMbHeight = pSps->iMbHeight;
263 int32_t iRet = ERR_NONE;
264 if (FmoParamSetsChanged (pFmo, kuiMbWidth * kuiMbHeight, pPps->uiSliceGroupMapType, pPps->uiNumSliceGroups)) {
265 iRet = InitFmo (pFmo, pPps, kuiMbWidth, kuiMbHeight, pMa);
266 WELS_VERIFY_RETURN_IF (iRet, iRet);
267
268 if (!pFmo->bActiveFlag && *pActiveFmoNum < MAX_PPS_COUNT) {
269 ++ (*pActiveFmoNum);
270 pFmo->bActiveFlag = true;
271 }
272 }
273 return iRet;
274 }
275
276 /*!
277 * \brief Convert kMbXy to slice group idc correspondingly
278 *
279 * \param pFmo Wels fmo context
280 * \param kMbXy kMbXy to be converted
281 *
282 * \return slice group idc - successful; -1 - failed;
283 */
FmoMbToSliceGroup(PFmo pFmo,const MB_XY_T kiMbXy)284 int32_t FmoMbToSliceGroup (PFmo pFmo, const MB_XY_T kiMbXy) {
285 const int32_t kiMbNum = pFmo->iCountMbNum;
286 const uint8_t* kpMbMap = pFmo->pMbAllocMap;
287
288 if (kiMbXy < 0 || kiMbXy >= kiMbNum || kpMbMap == NULL)
289 return -1;
290
291 return kpMbMap[ kiMbXy ];
292 }
293
294 /*!
295 * \brief Get successive mb to be processed with given current kMbXy
296 *
297 * \param pFmo Wels fmo context
298 * \param kMbXy current kMbXy
299 *
300 * \return iNextMb - successful; -1 - failed;
301 */
FmoNextMb(PFmo pFmo,const MB_XY_T kiMbXy)302 MB_XY_T FmoNextMb (PFmo pFmo, const MB_XY_T kiMbXy) {
303 const int32_t kiTotalMb = pFmo->iCountMbNum;
304 const uint8_t* kpMbMap = pFmo->pMbAllocMap;
305 MB_XY_T iNextMb = kiMbXy;
306 const uint8_t kuiSliceGroupIdc = (uint8_t)FmoMbToSliceGroup (pFmo, kiMbXy);
307
308 if (kuiSliceGroupIdc == (uint8_t) (-1))
309 return -1;
310
311 do {
312 ++ iNextMb;
313 if (iNextMb >= kiTotalMb) {
314 iNextMb = -1;
315 break;
316 }
317 if (kpMbMap[iNextMb] == kuiSliceGroupIdc) {
318 break;
319 }
320 } while (1);
321
322 // -1: No further MB in this slice (could be end of picture)
323 return iNextMb;
324 }
325
326 } // namespace WelsDec
327