1 
2 /*!
3  *****************************************************************************
4  *
5  * \file fmo.c
6  *
7  * \brief
8  *    Support for Flexible Macroblock Ordering (FMO)
9  *
10  * \author
11  *    Main contributors (see contributors.h for copyright, address and affiliation details)
12  *    - Stephan Wenger      stewe@cs.tu-berlin.de
13  *    - Karsten Suehring
14  ******************************************************************************
15  */
16 
17 #include "global.h"
18 #include "elements.h"
19 #include "defines.h"
20 #include "header.h"
21 #include "fmo.h"
22 #include "fast_memory.h"
23 
24 //#define PRINT_FMO_MAPS
25 
26 static void FmoGenerateType0MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits );
27 static void FmoGenerateType1MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits );
28 static void FmoGenerateType2MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits );
29 static void FmoGenerateType3MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice );
30 static void FmoGenerateType4MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice );
31 static void FmoGenerateType5MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice );
32 static void FmoGenerateType6MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits );
33 
34 
35 /*!
36  ************************************************************************
37  * \brief
38  *    Generates p_Vid->MapUnitToSliceGroupMap
39  *    Has to be called every time a new Picture Parameter Set is used
40  *
41  * \param p_Vid
42  *      video encoding parameters for current picture
43  *
44  ************************************************************************
45  */
FmoGenerateMapUnitToSliceGroupMap(VideoParameters * p_Vid,Slice * currSlice)46 static int FmoGenerateMapUnitToSliceGroupMap (VideoParameters *p_Vid, Slice *currSlice)
47 {
48   seq_parameter_set_rbsp_t* sps = p_Vid->active_sps;
49   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
50 
51   unsigned int NumSliceGroupMapUnits;
52 
53   NumSliceGroupMapUnits = (sps->pic_height_in_map_units_minus1+1)* (sps->pic_width_in_mbs_minus1+1);
54 
55   if (pps->slice_group_map_type == 6)
56   {
57     if ((pps->pic_size_in_map_units_minus1 + 1) != NumSliceGroupMapUnits)
58     {
59       error ("wrong pps->pic_size_in_map_units_minus1 for used SPS and FMO type 6", 500);
60     }
61   }
62 
63   // allocate memory for p_Vid->MapUnitToSliceGroupMap
64   if (p_Vid->MapUnitToSliceGroupMap)
65     free (p_Vid->MapUnitToSliceGroupMap);
66   if ((p_Vid->MapUnitToSliceGroupMap = malloc ((NumSliceGroupMapUnits) * sizeof (int))) == NULL)
67   {
68     printf ("cannot allocated %d bytes for p_Vid->MapUnitToSliceGroupMap, exit\n", (int) ( (pps->pic_size_in_map_units_minus1+1) * sizeof (int)));
69     exit (-1);
70   }
71 
72   if (pps->num_slice_groups_minus1 == 0)    // only one slice group
73   {
74     fast_memset (p_Vid->MapUnitToSliceGroupMap, 0, NumSliceGroupMapUnits * sizeof (int));
75     return 0;
76   }
77 
78   switch (pps->slice_group_map_type)
79   {
80   case 0:
81     FmoGenerateType0MapUnitMap (p_Vid, NumSliceGroupMapUnits);
82     break;
83   case 1:
84     FmoGenerateType1MapUnitMap (p_Vid, NumSliceGroupMapUnits);
85     break;
86   case 2:
87     FmoGenerateType2MapUnitMap (p_Vid, NumSliceGroupMapUnits);
88     break;
89   case 3:
90     FmoGenerateType3MapUnitMap (p_Vid, NumSliceGroupMapUnits, currSlice);
91     break;
92   case 4:
93     FmoGenerateType4MapUnitMap (p_Vid, NumSliceGroupMapUnits, currSlice);
94     break;
95   case 5:
96     FmoGenerateType5MapUnitMap (p_Vid, NumSliceGroupMapUnits, currSlice);
97     break;
98   case 6:
99     FmoGenerateType6MapUnitMap (p_Vid, NumSliceGroupMapUnits);
100     break;
101   default:
102     printf ("Illegal slice_group_map_type %d , exit \n", (int) pps->slice_group_map_type);
103     exit (-1);
104   }
105   return 0;
106 }
107 
108 
109 /*!
110  ************************************************************************
111  * \brief
112  *    Generates p_Vid->MbToSliceGroupMap from p_Vid->MapUnitToSliceGroupMap
113  *
114  * \param p_Vid
115  *      video encoding parameters for current picture
116  *
117  ************************************************************************
118  */
FmoGenerateMbToSliceGroupMap(VideoParameters * p_Vid,Slice * pSlice)119 static int FmoGenerateMbToSliceGroupMap (VideoParameters *p_Vid, Slice *pSlice)
120 {
121   seq_parameter_set_rbsp_t* sps = p_Vid->active_sps;
122 
123   unsigned i;
124 
125   // allocate memory for p_Vid->MbToSliceGroupMap
126   if (p_Vid->MbToSliceGroupMap)
127     free (p_Vid->MbToSliceGroupMap);
128 
129   if ((p_Vid->MbToSliceGroupMap = malloc ((p_Vid->PicSizeInMbs) * sizeof (int))) == NULL)
130   {
131     printf ("cannot allocate %d bytes for p_Vid->MbToSliceGroupMap, exit\n", (int) ((p_Vid->PicSizeInMbs) * sizeof (int)));
132     exit (-1);
133   }
134 
135 
136   if ((sps->frame_mbs_only_flag)|| pSlice->field_pic_flag)
137   {
138     int *MbToSliceGroupMap = p_Vid->MbToSliceGroupMap;
139     int *MapUnitToSliceGroupMap = p_Vid->MapUnitToSliceGroupMap;
140     for (i=0; i<p_Vid->PicSizeInMbs; i++)
141     {
142       *MbToSliceGroupMap++ = *MapUnitToSliceGroupMap++;
143     }
144   }
145   else
146     if (sps->mb_adaptive_frame_field_flag  &&  (!pSlice->field_pic_flag))
147     {
148       for (i=0; i<p_Vid->PicSizeInMbs; i++)
149       {
150         p_Vid->MbToSliceGroupMap[i] = p_Vid->MapUnitToSliceGroupMap[i/2];
151       }
152     }
153     else
154     {
155       for (i=0; i<p_Vid->PicSizeInMbs; i++)
156       {
157         p_Vid->MbToSliceGroupMap[i] = p_Vid->MapUnitToSliceGroupMap[(i/(2*p_Vid->PicWidthInMbs))*p_Vid->PicWidthInMbs+(i%p_Vid->PicWidthInMbs)];
158       }
159     }
160   return 0;
161 }
162 
163 
164 /*!
165  ************************************************************************
166  * \brief
167  *    FMO initialization: Generates p_Vid->MapUnitToSliceGroupMap and p_Vid->MbToSliceGroupMap.
168  *
169  * \param p_Vid
170  *      video encoding parameters for current picture
171  ************************************************************************
172  */
fmo_init(VideoParameters * p_Vid,Slice * pSlice)173 int fmo_init(VideoParameters *p_Vid, Slice *pSlice)
174 {
175   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
176 
177 #ifdef PRINT_FMO_MAPS
178   unsigned i,j;
179 #endif
180 
181   FmoGenerateMapUnitToSliceGroupMap(p_Vid, pSlice);
182   FmoGenerateMbToSliceGroupMap(p_Vid, pSlice);
183 
184   p_Vid->NumberOfSliceGroups = pps->num_slice_groups_minus1 + 1;
185 
186 #ifdef PRINT_FMO_MAPS
187   printf("\n");
188   printf("FMO Map (Units):\n");
189 
190   for (j=0; j<p_Vid->PicHeightInMapUnits; j++)
191   {
192     for (i=0; i<p_Vid->PicWidthInMbs; i++)
193     {
194       printf("%c",48+p_Vid->MapUnitToSliceGroupMap[i+j*p_Vid->PicWidthInMbs]);
195     }
196     printf("\n");
197   }
198   printf("\n");
199   printf("FMO Map (Mb):\n");
200 
201   for (j=0; j<p_Vid->PicHeightInMbs; j++)
202   {
203     for (i=0; i<p_Vid->PicWidthInMbs; i++)
204     {
205       printf("%c",48 + p_Vid->MbToSliceGroupMap[i + j * p_Vid->PicWidthInMbs]);
206     }
207     printf("\n");
208   }
209   printf("\n");
210 
211 #endif
212 
213   return 0;
214 }
215 
216 
217 /*!
218  ************************************************************************
219  * \brief
220  *    Free memory allocated by FMO functions
221  ************************************************************************
222  */
FmoFinit(VideoParameters * p_Vid)223 int FmoFinit(VideoParameters *p_Vid)
224 {
225   if (p_Vid->MbToSliceGroupMap)
226   {
227     free (p_Vid->MbToSliceGroupMap);
228     p_Vid->MbToSliceGroupMap = NULL;
229   }
230   if (p_Vid->MapUnitToSliceGroupMap)
231   {
232     free (p_Vid->MapUnitToSliceGroupMap);
233     p_Vid->MapUnitToSliceGroupMap = NULL;
234   }
235   return 0;
236 }
237 
238 
239 /*!
240  ************************************************************************
241  * \brief
242  *    FmoGetNumberOfSliceGroup(p_Vid)
243  *
244  * \par p_Vid:
245  *    VideoParameters
246  ************************************************************************
247  */
FmoGetNumberOfSliceGroup(VideoParameters * p_Vid)248 int FmoGetNumberOfSliceGroup(VideoParameters *p_Vid)
249 {
250   return p_Vid->NumberOfSliceGroups;
251 }
252 
253 
254 /*!
255  ************************************************************************
256  * \brief
257  *    FmoGetLastMBOfPicture(p_Vid)
258  *    returns the macroblock number of the last MB in a picture.  This
259  *    mb happens to be the last macroblock of the picture if there is only
260  *    one slice group
261  *
262  * \par Input:
263  *    None
264  ************************************************************************
265  */
FmoGetLastMBOfPicture(VideoParameters * p_Vid)266 int FmoGetLastMBOfPicture(VideoParameters *p_Vid)
267 {
268   return FmoGetLastMBInSliceGroup (p_Vid, FmoGetNumberOfSliceGroup(p_Vid)-1);
269 }
270 
271 
272 /*!
273  ************************************************************************
274  * \brief
275  *    FmoGetLastMBInSliceGroup: Returns MB number of last MB in SG
276  *
277  * \par Input:
278  *    SliceGroupID (0 to 7)
279  ************************************************************************
280  */
281 
FmoGetLastMBInSliceGroup(VideoParameters * p_Vid,int SliceGroup)282 int FmoGetLastMBInSliceGroup (VideoParameters *p_Vid, int SliceGroup)
283 {
284   int i;
285 
286   for (i=p_Vid->PicSizeInMbs-1; i>=0; i--)
287     if (FmoGetSliceGroupId (p_Vid, i) == SliceGroup)
288       return i;
289   return -1;
290 
291 }
292 
293 
294 /*!
295  ************************************************************************
296  * \brief
297  *    Returns SliceGroupID for a given MB
298  *
299  * \param p_Vid
300  *      video encoding parameters for current picture
301  * \param mb
302  *    Macroblock number (in scan order)
303  ************************************************************************
304  */
FmoGetSliceGroupId(VideoParameters * p_Vid,int mb)305 int FmoGetSliceGroupId (VideoParameters *p_Vid, int mb)
306 {
307   assert (mb < (int) p_Vid->PicSizeInMbs);
308   assert (p_Vid->MbToSliceGroupMap != NULL);
309   return p_Vid->MbToSliceGroupMap[mb];
310 }
311 
312 
313 /*!
314  ************************************************************************
315  * \brief
316  *    FmoGetNextMBBr: Returns the MB-Nr (in scan order) of the next
317  *    MB in the (scattered) Slice, -1 if the slice is finished
318  * \param p_Vid
319  *      video encoding parameters for current picture
320  *
321  * \param CurrentMbNr
322  *    number of the current macroblock
323  ************************************************************************
324  */
FmoGetNextMBNr(VideoParameters * p_Vid,int CurrentMbNr)325 int FmoGetNextMBNr (VideoParameters *p_Vid, int CurrentMbNr)
326 {
327   int SliceGroup = FmoGetSliceGroupId (p_Vid, CurrentMbNr);
328 
329   while (++CurrentMbNr<(int)p_Vid->PicSizeInMbs && p_Vid->MbToSliceGroupMap [CurrentMbNr] != SliceGroup)
330     ;
331 
332   if (CurrentMbNr >= (int)p_Vid->PicSizeInMbs)
333     return -1;    // No further MB in this slice (could be end of picture)
334   else
335     return CurrentMbNr;
336 }
337 
338 
339 /*!
340  ************************************************************************
341  * \brief
342  *    Generate interleaved slice group map type MapUnit map (type 0)
343  *
344  ************************************************************************
345  */
FmoGenerateType0MapUnitMap(VideoParameters * p_Vid,unsigned PicSizeInMapUnits)346 static void FmoGenerateType0MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits )
347 {
348   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
349   unsigned iGroup, j;
350   unsigned i = 0;
351   do
352   {
353     for( iGroup = 0;
354          (iGroup <= pps->num_slice_groups_minus1) && (i < PicSizeInMapUnits);
355          i += pps->run_length_minus1[iGroup++] + 1 )
356     {
357       for( j = 0; j <= pps->run_length_minus1[ iGroup ] && i + j < PicSizeInMapUnits; j++ )
358         p_Vid->MapUnitToSliceGroupMap[i+j] = iGroup;
359     }
360   }
361   while( i < PicSizeInMapUnits );
362 }
363 
364 
365 /*!
366  ************************************************************************
367  * \brief
368  *    Generate dispersed slice group map type MapUnit map (type 1)
369  *
370  ************************************************************************
371  */
FmoGenerateType1MapUnitMap(VideoParameters * p_Vid,unsigned PicSizeInMapUnits)372 static void FmoGenerateType1MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits )
373 {
374   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
375   unsigned i;
376   for( i = 0; i < PicSizeInMapUnits; i++ )
377   {
378     p_Vid->MapUnitToSliceGroupMap[i] = ((i%p_Vid->PicWidthInMbs)+(((i/p_Vid->PicWidthInMbs)*(pps->num_slice_groups_minus1+1))/2))
379                                 %(pps->num_slice_groups_minus1+1);
380   }
381 }
382 
383 /*!
384  ************************************************************************
385  * \brief
386  *    Generate foreground with left-over slice group map type MapUnit map (type 2)
387  *
388  ************************************************************************
389  */
FmoGenerateType2MapUnitMap(VideoParameters * p_Vid,unsigned PicSizeInMapUnits)390 static void FmoGenerateType2MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits )
391 {
392   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
393   int iGroup;
394   unsigned i, x, y;
395   unsigned yTopLeft, xTopLeft, yBottomRight, xBottomRight;
396 
397   for( i = 0; i < PicSizeInMapUnits; i++ )
398     p_Vid->MapUnitToSliceGroupMap[ i ] = pps->num_slice_groups_minus1;
399 
400   for( iGroup = pps->num_slice_groups_minus1 - 1 ; iGroup >= 0; iGroup-- )
401   {
402     yTopLeft = pps->top_left[ iGroup ] / p_Vid->PicWidthInMbs;
403     xTopLeft = pps->top_left[ iGroup ] % p_Vid->PicWidthInMbs;
404     yBottomRight = pps->bottom_right[ iGroup ] / p_Vid->PicWidthInMbs;
405     xBottomRight = pps->bottom_right[ iGroup ] % p_Vid->PicWidthInMbs;
406     for( y = yTopLeft; y <= yBottomRight; y++ )
407       for( x = xTopLeft; x <= xBottomRight; x++ )
408         p_Vid->MapUnitToSliceGroupMap[ y * p_Vid->PicWidthInMbs + x ] = iGroup;
409  }
410 }
411 
412 
413 /*!
414  ************************************************************************
415  * \brief
416  *    Generate box-out slice group map type MapUnit map (type 3)
417  *
418  ************************************************************************
419  */
FmoGenerateType3MapUnitMap(VideoParameters * p_Vid,unsigned PicSizeInMapUnits,Slice * currSlice)420 static void FmoGenerateType3MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice )
421 {
422   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
423   unsigned i, k;
424   int leftBound, topBound, rightBound, bottomBound;
425   int x, y, xDir, yDir;
426   int mapUnitVacant;
427 
428   unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * currSlice->slice_group_change_cycle, PicSizeInMapUnits);
429 
430   for( i = 0; i < PicSizeInMapUnits; i++ )
431     p_Vid->MapUnitToSliceGroupMap[ i ] = 2;
432 
433   x = ( p_Vid->PicWidthInMbs - pps->slice_group_change_direction_flag ) / 2;
434   y = ( p_Vid->PicHeightInMapUnits - pps->slice_group_change_direction_flag ) / 2;
435 
436   leftBound   = x;
437   topBound    = y;
438   rightBound  = x;
439   bottomBound = y;
440 
441   xDir =  pps->slice_group_change_direction_flag - 1;
442   yDir =  pps->slice_group_change_direction_flag;
443 
444   for( k = 0; k < PicSizeInMapUnits; k += mapUnitVacant )
445   {
446     mapUnitVacant = ( p_Vid->MapUnitToSliceGroupMap[ y * p_Vid->PicWidthInMbs + x ]  ==  2 );
447     if( mapUnitVacant )
448        p_Vid->MapUnitToSliceGroupMap[ y * p_Vid->PicWidthInMbs + x ] = ( k >= mapUnitsInSliceGroup0 );
449 
450     if( xDir  ==  -1  &&  x  ==  leftBound )
451     {
452       leftBound = imax( leftBound - 1, 0 );
453       x = leftBound;
454       xDir = 0;
455       yDir = 2 * pps->slice_group_change_direction_flag - 1;
456     }
457     else
458       if( xDir  ==  1  &&  x  ==  rightBound )
459       {
460         rightBound = imin( rightBound + 1, (int)p_Vid->PicWidthInMbs - 1 );
461         x = rightBound;
462         xDir = 0;
463         yDir = 1 - 2 * pps->slice_group_change_direction_flag;
464       }
465       else
466         if( yDir  ==  -1  &&  y  ==  topBound )
467         {
468           topBound = imax( topBound - 1, 0 );
469           y = topBound;
470           xDir = 1 - 2 * pps->slice_group_change_direction_flag;
471           yDir = 0;
472          }
473         else
474           if( yDir  ==  1  &&  y  ==  bottomBound )
475           {
476             bottomBound = imin( bottomBound + 1, (int)p_Vid->PicHeightInMapUnits - 1 );
477             y = bottomBound;
478             xDir = 2 * pps->slice_group_change_direction_flag - 1;
479             yDir = 0;
480           }
481           else
482           {
483             x = x + xDir;
484             y = y + yDir;
485           }
486   }
487 
488 }
489 
490 /*!
491  ************************************************************************
492  * \brief
493  *    Generate raster scan slice group map type MapUnit map (type 4)
494  *
495  ************************************************************************
496  */
FmoGenerateType4MapUnitMap(VideoParameters * p_Vid,unsigned PicSizeInMapUnits,Slice * currSlice)497 static void FmoGenerateType4MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice )
498 {
499   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
500 
501   unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * currSlice->slice_group_change_cycle, PicSizeInMapUnits);
502   unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0;
503 
504   unsigned i;
505 
506   for( i = 0; i < PicSizeInMapUnits; i++ )
507     if( i < sizeOfUpperLeftGroup )
508         p_Vid->MapUnitToSliceGroupMap[ i ] = pps->slice_group_change_direction_flag;
509     else
510         p_Vid->MapUnitToSliceGroupMap[ i ] = 1 - pps->slice_group_change_direction_flag;
511 
512 }
513 
514 /*!
515  ************************************************************************
516  * \brief
517  *    Generate wipe slice group map type MapUnit map (type 5)
518  *
519  ************************************************************************
520  */
FmoGenerateType5MapUnitMap(VideoParameters * p_Vid,unsigned PicSizeInMapUnits,Slice * currSlice)521 static void FmoGenerateType5MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice )
522 {
523   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
524 
525   unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * currSlice->slice_group_change_cycle, PicSizeInMapUnits);
526   unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0;
527 
528   unsigned i,j, k = 0;
529 
530   for( j = 0; j < p_Vid->PicWidthInMbs; j++ )
531     for( i = 0; i < p_Vid->PicHeightInMapUnits; i++ )
532         if( k++ < sizeOfUpperLeftGroup )
533             p_Vid->MapUnitToSliceGroupMap[ i * p_Vid->PicWidthInMbs + j ] = pps->slice_group_change_direction_flag;
534         else
535             p_Vid->MapUnitToSliceGroupMap[ i * p_Vid->PicWidthInMbs + j ] = 1 - pps->slice_group_change_direction_flag;
536 
537 }
538 
539 /*!
540  ************************************************************************
541  * \brief
542  *    Generate explicit slice group map type MapUnit map (type 6)
543  *
544  ************************************************************************
545  */
FmoGenerateType6MapUnitMap(VideoParameters * p_Vid,unsigned PicSizeInMapUnits)546 static void FmoGenerateType6MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits )
547 {
548   pic_parameter_set_rbsp_t* pps = p_Vid->active_pps;
549   unsigned i;
550   for (i=0; i<PicSizeInMapUnits; i++)
551   {
552     p_Vid->MapUnitToSliceGroupMap[i] = pps->slice_group_id[i];
553   }
554 }
555 
556