package org.jcodec.codecs.h264.decode.aso; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * A helper class that builds macroblock to slice group maps needed by ASO * (Arbitrary Slice Order) * * @author The JCodec project * */ public class SliceGroupMapBuilder { /** * * Interleaved slice group map. Each slice group fills a number of cells * equal to the appropriate run length, then followed by the next slice * group. * * Example: * * 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, * */ public static int[] buildInterleavedMap(int picWidthInMbs, int picHeightInMbs, int[] runLength) { int numSliceGroups = runLength.length; int picSizeInMbs = picWidthInMbs * picHeightInMbs; int[] groups = new int[picSizeInMbs]; int i = 0; do { for (int iGroup = 0; iGroup < numSliceGroups && i < picSizeInMbs; i += runLength[iGroup++]) { for (int j = 0; j < runLength[iGroup] && i + j < picSizeInMbs; j++) { groups[i + j] = iGroup; } } } while (i < picSizeInMbs); return groups; } /** * A dispersed map. Every odd line starts from the (N / 2)th group * * Example: * * 0, 1, 2, 3, 0, 1, 2, 3 2, 3, 0, 1, 2, 3, 0, 1 0, 1, 2, 3, 0, 1, 2, 3 2, * 3, 0, 1, 2, 3, 0, 1 0, 1, 2, 3, 0, 1, 2, 3 2, 3, 0, 1, 2, 3, 0, 1 0, 1, * 2, 3, 0, 1, 2, 3 2, 3, 0, 1, 2, 3, 0, 1 0, 1, 2, 3, 0, 1, 2, 3 2, 3, 0, * 1, 2, 3, 0, 1 * */ public static int[] buildDispersedMap(int picWidthInMbs, int picHeightInMbs, int numSliceGroups) { int picSizeInMbs = picWidthInMbs * picHeightInMbs; int[] groups = new int[picSizeInMbs]; for (int i = 0; i < picSizeInMbs; i++) { int group = ((i % picWidthInMbs) + (((i / picWidthInMbs) * numSliceGroups) / 2)) % numSliceGroups; groups[i] = group; } return groups; } /** * * A foreground macroblock to slice group map. Macroblocks of the last slice * group are the background, all the others represent rectangles covering * areas with top-left corner specified by topLeftAddr[group] and bottom * right corner specified by bottomRightAddr[group]. * * @param picWidthInMbs * @param picHeightInMbs * @param numSliceGroups * Total number of slice groups * @param topLeftAddr * Addresses of macroblocks that are top-left corners of * respective slice groups * @param bottomRightAddr * Addresses macroblocks that are bottom-right corners of * respective slice groups * @return */ public static int[] buildForegroundMap(int picWidthInMbs, int picHeightInMbs, int numSliceGroups, int[] topLeftAddr, int[] bottomRightAddr) { int picSizeInMbs = picWidthInMbs * picHeightInMbs; int[] groups = new int[picSizeInMbs]; for (int i = 0; i < picSizeInMbs; i++) groups[i] = numSliceGroups - 1; int tot = 0; for (int iGroup = numSliceGroups - 2; iGroup >= 0; iGroup--) { int yTopLeft = topLeftAddr[iGroup] / picWidthInMbs; int xTopLeft = topLeftAddr[iGroup] % picWidthInMbs; int yBottomRight = bottomRightAddr[iGroup] / picWidthInMbs; int xBottomRight = bottomRightAddr[iGroup] % picWidthInMbs; int sz = (yBottomRight - yTopLeft + 1) * (xBottomRight - xTopLeft + 1); tot += sz; int ind = 0; for (int y = yTopLeft; y <= yBottomRight; y++) for (int x = xTopLeft; x <= xBottomRight; x++) { int mbAddr = y * picWidthInMbs + x; groups[mbAddr] = iGroup; } } return groups; } /** * A boxout macroblock to slice group mapping. Only applicable when there's * exactly 2 slice groups. Slice group 1 is a background, while slice group * 0 is a box in the middle of the frame. * * @param picWidthInMbs * @param picHeightInMbs * @param changeDirection * @param numberOfMbsInBox * number of macroblocks in slice group 0 * @return */ public static int[] buildBoxOutMap(int picWidthInMbs, int picHeightInMbs, boolean changeDirection, int numberOfMbsInBox) { int picSizeInMbs = picWidthInMbs * picHeightInMbs; int[] groups = new int[picSizeInMbs]; int changeDirectionInt = changeDirection ? 1 : 0; for (int i = 0; i < picSizeInMbs; i++) groups[i] = 1; int x = (picWidthInMbs - changeDirectionInt) / 2; int y = (picHeightInMbs - changeDirectionInt) / 2; int leftBound = x; int topBound = y; int rightBound = x; int bottomBound = y; int xDir = changeDirectionInt - 1; int yDir = changeDirectionInt; boolean mapUnitVacant = false; for (int k = 0; k < numberOfMbsInBox; k += (mapUnitVacant ? 1 : 0)) { int mbAddr = y * picWidthInMbs + x; mapUnitVacant = (groups[mbAddr] == 1); if (mapUnitVacant) { groups[mbAddr] = 0; } if (xDir == -1 && x == leftBound) { leftBound = Max(leftBound - 1, 0); x = leftBound; xDir = 0; yDir = 2 * changeDirectionInt - 1; } else if (xDir == 1 && x == rightBound) { rightBound = Min(rightBound + 1, picWidthInMbs - 1); x = rightBound; xDir = 0; yDir = 1 - 2 * changeDirectionInt; } else if (yDir == -1 && y == topBound) { topBound = Max(topBound - 1, 0); y = topBound; xDir = 1 - 2 * changeDirectionInt; yDir = 0; } else if (yDir == 1 && y == bottomBound) { bottomBound = Min(bottomBound + 1, picHeightInMbs - 1); y = bottomBound; xDir = 2 * changeDirectionInt - 1; yDir = 0; } else { x += xDir; y += yDir; } } return groups; } private static int Min(int i, int j) { return i < j ? i : j; } private static int Max(int i, int j) { return i > j ? i : j; } /** * * A macroblock to slice group map that fills frame in raster scan. * * @param picWidthInMbs * @param picHeightInMbs * @param sizeOfUpperLeftGroup * @param changeDirection * @return */ public static int[] buildRasterScanMap(int picWidthInMbs, int picHeightInMbs, int sizeOfUpperLeftGroup, boolean changeDirection) { int picSizeInMbs = picWidthInMbs * picHeightInMbs; int[] groups = new int[picSizeInMbs]; int changeDirectionInt = changeDirection ? 1 : 0; int i; for (i = 0; i < sizeOfUpperLeftGroup; i++) { groups[i] = changeDirectionInt; } for (; i < picSizeInMbs; i++) { groups[i] = 1 - changeDirectionInt; } return groups; } /** * A macroblock to slice group map that fills frame column by column * * @param picWidthInMbs * @param picHeightInMbs * @param sizeOfUpperLeftGroup * @param changeDirection * @return */ public static int[] buildWipeMap(int picWidthInMbs, int picHeightInMbs, int sizeOfUpperLeftGroup, boolean changeDirection) { int picSizeInMbs = picWidthInMbs * picHeightInMbs; int[] groups = new int[picSizeInMbs]; int changeDirectionInt = changeDirection ? 1 : 0; int k = 0; for (int j = 0; j < picWidthInMbs; j++) { for (int i = 0; i < picHeightInMbs; i++) { int mbAddr = i * picWidthInMbs + j; if (k++ < sizeOfUpperLeftGroup) { groups[mbAddr] = changeDirectionInt; } else { groups[mbAddr] = 1 - changeDirectionInt; } } } return groups; } }