• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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