org.jcodec.codecs.h264.decode.resilence.Painter.java Source code

Java tutorial

Introduction

Here is the source code for org.jcodec.codecs.h264.decode.resilence.Painter.java

Source

package org.jcodec.codecs.h264.decode.resilence;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import org.apache.commons.io.IOUtils;
import org.jcodec.codecs.h264.decode.model.DecodedChroma;
import org.jcodec.codecs.h264.decode.model.DecodedMBlock;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 * 
 * Paints macroblock content using it's bourders as a basis. The macroblock is
 * painted the way the border distortion is kept to minimum.
 * 
 * @author Jay Codec
 * 
 */
public class Painter {

    public DecodedMBlock paintMBlock(DecodedMBlock left, DecodedMBlock top, DecodedMBlock right,
            DecodedMBlock bottom) {

        int[] leftPixY = null;
        int[] leftPixCb = null;
        int[] leftPixCr = null;
        if (left != null) {
            leftPixY = new int[16];
            leftPixCb = new int[8];
            leftPixCr = new int[8];
            for (int i = 0; i < 16; i++) {
                leftPixY[i] = left.getLuma()[(i << 4) + 15];
            }

            for (int i = 0; i < 8; i++) {
                leftPixCb[i] = left.getChroma().getCb()[(i << 3) + 7];
                leftPixCr[i] = left.getChroma().getCr()[(i << 3) + 7];
            }
        }

        int[] topPixY = null;
        int[] topPixCb = null;
        int[] topPixCr = null;
        if (top != null) {
            topPixY = new int[16];
            topPixCb = new int[8];
            topPixCr = new int[8];
            for (int i = 0; i < 16; i++) {
                topPixY[i] = top.getLuma()[240 + i];
            }

            for (int i = 0; i < 8; i++) {
                topPixCb[i] = top.getChroma().getCb()[56 + i];
                topPixCr[i] = top.getChroma().getCr()[56 + i];
            }
        }

        int[] rightPixY = null;
        int[] rightPixCb = null;
        int[] rightPixCr = null;
        if (right != null) {
            rightPixY = new int[16];
            rightPixCb = new int[8];
            rightPixCr = new int[8];
            for (int i = 0; i < 16; i++) {
                rightPixY[i] = right.getLuma()[(i << 4) + 15];
            }

            for (int i = 0; i < 8; i++) {
                rightPixCb[i] = right.getChroma().getCb()[(i << 3) + 7];
                rightPixCr[i] = right.getChroma().getCr()[(i << 3) + 7];
            }
        }

        int[] bottomPixY = null;
        int[] bottomPixCb = null;
        int[] bottomPixCr = null;
        if (bottom != null) {
            bottomPixY = new int[16];
            bottomPixCb = new int[8];
            bottomPixCr = new int[8];
            for (int i = 0; i < 16; i++) {
                bottomPixY[i] = bottom.getLuma()[240 + i];
            }

            for (int i = 0; i < 8; i++) {
                bottomPixCb[i] = bottom.getChroma().getCb()[56 + i];
                bottomPixCr[i] = bottom.getChroma().getCr()[56 + i];
            }
        }

        int[] cb = paintChroma(leftPixCb, topPixCb, rightPixCb, bottomPixCb);
        int[] cr = paintChroma(leftPixCr, topPixCr, rightPixCr, bottomPixCr);

        int[] luma;

        int cnt = (top != null ? 1 : 0) + (left != null ? 1 : 0) + (right != null ? 1 : 0)
                + (bottom != null ? 1 : 0);

        if (cnt == 4)
            luma = paintLuma4Sides(leftPixY, topPixY, rightPixY, bottomPixY);
        else if (cnt == 3) {
            if (top == null)
                luma = paintLuma3SidesLRB(leftPixY, rightPixY, bottomPixY);
            else if (bottom == null)
                luma = paintLuma3SidesLTR(leftPixY, topPixY, rightPixY);
            else if (left == null)
                luma = paintLuma3SidesTRB(topPixY, rightPixY, bottomPixY);
            else
                luma = paintLuma3SidesLTB(leftPixY, topPixY, bottomPixY);
        } else if (cnt == 2) {
            if (top != null && bottom != null)
                luma = paintLumaVert(topPixY, bottomPixY);
            else if (left != null && right != null)
                luma = paintLumaHor(leftPixY, rightPixY);
            else if (left != null) {
                if (top != null)
                    luma = paint2SideLuma(leftPixY, topPixY);
                else
                    luma = paint2SideLuma(leftPixY, bottomPixY);
            } else {
                if (top != null)
                    luma = paint2SideLuma(rightPixY, topPixY);
                else
                    luma = paint2SideLuma(rightPixY, bottomPixY);
            }
        } else {
            if (top != null)
                luma = paintLumaVer(topPixY);
            else if (left != null)
                luma = paintLumaHor(leftPixY);
            else if (right != null)
                luma = paintLumaHor(rightPixY);
            else
                luma = paintLumaVer(bottomPixY);
        }

        return new DecodedMBlock(luma, new DecodedChroma(cb, cr, 0, 0), 0, null, null, null);

    }

    private int[] paintLumaHor(int[] leftPixY, int[] rightPixY) {
        int[] luma = new int[256];

        for (int j = 0; j < 16; j++) {
            int off = j << 4;
            luma[off + 8] = (leftPixY[j] + rightPixY[j] + 1) >> 1;
            luma[off + 12] = (luma[off + 8] + rightPixY[j] + 1) >> 1;
            luma[off + 4] = (luma[off + 8] + leftPixY[j] + 1) >> 1;

            luma[off + 1] = luma[off + 2] = (leftPixY[j] + luma[off + 4] + 1) >> 1;
            luma[off + 6] = (luma[off + 4] + luma[off + 8] + 1) >> 1;
            luma[off + 10] = (luma[off + 8] + luma[off + 12] + 1) >> 1;
            luma[off + 14] = (luma[off + 12] + rightPixY[j] + 1) >> 1;

            luma[off + 0] = (leftPixY[j] + luma[off + 1] + 1) >> 1;
            luma[off + 3] = (luma[off + 2] + luma[off + 4] + 1) >> 1;
            luma[off + 5] = (luma[off + 4] + luma[off + 6] + 1) >> 1;
            luma[off + 7] = (luma[off + 6] + luma[off + 8] + 1) >> 1;
            luma[off + 9] = (luma[off + 8] + luma[off + 10] + 1) >> 1;
            luma[off + 11] = (luma[off + 10] + luma[off + 12] + 1) >> 1;
            luma[off + 13] = (luma[off + 12] + luma[off + 14] + 1) >> 1;
            luma[off + 15] = (luma[off + 14] + rightPixY[j] + 1) >> 1;
        }
        return luma;
    }

    private int[] paintLumaVert(int[] topPixY, int[] bottomPixY) {
        int[] luma = new int[256];

        for (int i = 0; i < 16; i++) {
            luma[i + 128] = (topPixY[i] + bottomPixY[i] + 1) >> 1;
            luma[i + 192] = (luma[i + 128] + bottomPixY[i] + 1) >> 1;
            luma[i + 64] = (luma[i + 128] + topPixY[i] + 1) >> 1;

            luma[i + 16] = luma[i + 32] = (topPixY[i] + luma[i + 64] + 1) >> 1;
            luma[i + 96] = (luma[i + 64] + luma[i + 128] + 1) >> 1;
            luma[i + 160] = (luma[i + 128] + luma[i + 192] + 1) >> 1;
            luma[i + 224] = (luma[i + 192] + bottomPixY[i] + 1) >> 1;

            luma[i] = (topPixY[i] + luma[i + 16] + 1) >> 1;
            luma[i + 48] = (luma[i + 32] + luma[i + 64] + 1) >> 1;
            luma[i + 80] = (luma[i + 64] + luma[i + 96] + 1) >> 1;
            luma[i + 112] = (luma[i + 96] + luma[i + 128] + 1) >> 1;
            luma[i + 144] = (luma[i + 128] + luma[i + 160] + 1) >> 1;
            luma[i + 176] = (luma[i + 160] + luma[i + 192] + 1) >> 1;
            luma[i + 208] = (luma[i + 192] + luma[i + 224] + 1) >> 1;
            luma[i + 240] = (luma[i + 224] + bottomPixY[i] + 1) >> 1;
        }
        return luma;
    }

    private int[] paintLumaHor(int[] leftPixY) {
        int[] luma = new int[256];

        for (int j = 0; j < 16; j++) {
            for (int i = 0; i < 16; i++) {
                luma[(j << 4) + i] = leftPixY[j];
            }
        }
        return luma;
    }

    private int[] paintLumaVer(int[] topPixY) {
        int[] luma = new int[256];

        for (int i = 0; i < 16; i++) {
            for (int j = 0; j < 16; j++) {
                luma[(j << 4) + i] = topPixY[i];
            }
        }
        return luma;
    }

    private int[] paintLuma3SidesLTB(int[] leftPixY, int[] topPixY, int[] bottomPixY) {

        int[] one = paintLumaVert(topPixY, bottomPixY);

        int[] right = new int[16];
        for (int j = 0; j < 16; j++)
            right[j] = one[(j << 4) + 15];

        int[] two = paintLumaHor(leftPixY, right);

        for (int i = 0; i < 256; i++) {
            one[i] = (one[i] + two[i] + 1) >> 1;
        }

        return one;

    }

    private int[] paintLuma3SidesTRB(int[] topPixY, int[] rightPixY, int[] bottomPixY) {
        int[] one = paintLumaVert(topPixY, bottomPixY);

        int[] left = new int[16];
        for (int j = 0; j < 16; j++)
            left[j] = one[j << 4];

        int[] two = paintLumaHor(left, rightPixY);

        for (int i = 0; i < 256; i++) {
            one[i] = (one[i] + two[i] + 1) >> 1;
        }

        return one;

    }

    private int[] paintLuma3SidesLTR(int[] leftPixY, int[] topPixY, int[] rightPixY) {

        int[] one = paintLumaHor(leftPixY, rightPixY);

        int[] bottom = new int[16];
        for (int i = 0; i < 16; i++)
            bottom[i] = one[240 + i];

        int[] two = paintLumaVert(topPixY, bottom);

        for (int i = 0; i < 256; i++) {
            one[i] = (one[i] + two[i] + 1) >> 1;
        }

        return one;
    }

    private int[] paintLuma3SidesLRB(int[] leftPixY, int[] rightPixY, int[] bottomPixY) {
        int[] one = paintLumaHor(leftPixY, rightPixY);

        int[] two = paintLumaVert(one, bottomPixY);

        for (int i = 0; i < 256; i++) {
            one[i] = (one[i] + two[i] + 1) >> 1;
        }

        return one;
    }

    private int[] paintLuma4Sides(int[] leftPixY, int[] topPixY, int[] rightPixY, int[] bottomPixY) {
        int[] one = paintLumaHor(leftPixY, rightPixY);
        int[] two = paintLumaVert(topPixY, bottomPixY);

        for (int i = 0; i < 256; i++) {
            one[i] = (one[i] + two[i] + 1) >> 1;
        }

        return one;
    }

    private int[] paintChroma(int[] left, int[] top, int[] right, int[] bottom) {
        int[] result = new int[64];

        int sum = 0;
        int count = 0;

        if (left != null) {
            for (int i = 0; i < 8; i++)
                sum += left[i];
            count += 8;
        }

        if (top != null) {
            for (int i = 0; i < 8; i++)
                sum += top[i];
            count += 8;
        }

        if (right != null) {
            for (int i = 0; i < 8; i++)
                sum += right[i];
            count += 8;
        }

        if (bottom != null) {
            for (int i = 0; i < 8; i++)
                sum += bottom[i];
            count += 8;
        }

        int val = sum / count;

        for (int i = 0; i < 64; i++)
            result[i] = val;

        return result;
    }

    private int[] paint2SideLuma(int[] sideA, int[] sideB) {
        int[] one = paintLumaHor(sideA);
        int[] two = paintLumaVer(sideB);

        for (int i = 0; i < 256; i++) {
            one[i] = (one[i] + two[i] + 1) >> 1;
        }

        return one;
    }

    public static void savePGM(String string, int[] y, int width, int height) {
        OutputStream out = null;
        try {
            out = new BufferedOutputStream(new FileOutputStream(string));

            PrintStream ps = new PrintStream(out);
            ps.println("P5");
            ps.println(width + " " + height);
            ps.println("255");
            ps.flush();

            for (int i = 0; i < y.length; i++)
                out.write(y[i]);

            out.flush();

        } catch (IOException e) {
            IOUtils.closeQuietly(out);
        }
    }
}