[FFmpeg-devel] GSoc Qualification Task - Implementing Compression technique B44 as a part of exr format (libavcodec/exr.c)

greeshma greeshmabalabadra at gmail.com
Mon Mar 16 19:19:09 CET 2015


Hello ,

I have implemented B44 lossy compression technique.The first patch is
hereby attached.Please have a look.
The diff file is also attached.

diff --git a/libavcodec/exr.c b/libavcodec/exr.c
index 6251fb7..e540d4c 100644
--- a/libavcodec/exr.c
+++ b/libavcodec/exr.c
@@ -45,6 +45,10 @@
 #include "mathops.h"
 #include "thread.h"

+typedef int bool;
+#define true 1
+#define false 0
+
 enum ExrCompr {
     EXR_RAW,
     EXR_RLE,
@@ -69,6 +73,19 @@ typedef struct EXRChannel {
     enum ExrPixelType pixel_type;
 } EXRChannel;

+
+typedef struct EXRChannelData
+{
+    unsigned short *    start;
+    unsigned short *    end;
+    int         nx;
+    int         ny;
+    int         ys;
+    enum ExrPixelType     type;
+    bool pLinear;
+    int         size;
+}EXRChannelData;
+
 typedef struct EXRThreadData {
     uint8_t *uncompressed_data;
     int uncompressed_size;

@@ -105,6 +122,8 @@ typedef struct EXRContext {

     EXRChannel *channels;
     int nb_channels;
+
+    EXRChannelData *channel_data;
     EXRThreadData *thread_data;

@@ -770,6 +789,259 @@ static int piz_uncompress(EXRContext *s, const
uint8_t *src, int ssize,
     return 0;
 }

+
+/*
+implemetation of B44_uncompress method which is a lossy compression method
which the following features
+
+compression rate 32/14
+works only on channels of HALF .It'll not work on FLOAT and UINT
+the compression method is as follows: It interprets 32byte input data as
16 - 16 bit integers
+It divides it into blocks of 4 by 4 pixels.Itt compresses 16 into 14 bytes.
+
+//-----------------------------------------------------------------------------
+//
+//
+//
+//  This compressor is lossy for HALF channels; the compression rate
+//  is fixed at 32/14 (approximately 2.28).  FLOAT and UINT channels
+//  are not compressed; their data are preserved exactly.
+//
+//  Each HALF channel is split into blocks of 4 by 4 pixels.  An
+//  uncompressed block occupies 32 bytes, which are re-interpreted
+//  as sixteen 16-bit unsigned integers, t[0] ... t[15].  Compression
+//  shrinks the block to 14 bytes.  The compressed 14-byte block
+//  contains
+//
+//   - t[0]
+//
+//   - a 6-bit shift value
+//
+//   - 15 densely packed 6-bit values, r[0] ... r[14], which are
+//         computed by subtracting adjacent pixel values and right-
+//     shifting the differences according to the stored shift value.
+//
+//     Differences between adjacent pixels are computed according
+//     to the following diagram:
+//
+//       0 -------->  1 -------->  2 -------->  3
+//               |     3            7           11
+//               |
+//               | 0
+//               |
+//               v
+//       4 -------->  5 -------->  6 -------->  7
+//               |     4            8           12
+//               |
+//               | 1
+//               |
+//               v
+//       8 -------->  9 --------> 10 --------> 11
+//               |     5            9           13
+//               |
+//               | 2
+//               |
+//               v
+//      12 --------> 13 --------> 14 --------> 15
+//                     6           10           14
+//
+//      Here
+//
+//               5 ---------> 6
+//                     8
+//
+//      means that r[8] is the difference between t[5] and t[6].
+//
+//   - optionally, a 4-by-4 pixel block where all pixels have the
+//     same value can be treated as a special case, where the
+//     compressed block contains only 3 instead of 14 bytes:
+//     t[0], followed by an "impossible" 6-bit shift value and
+//     two padding bits.
+//
+//  This compressor can handle positive and negative pixel values.
+//  NaNs and infinities are replaced with zeroes before compression.
+//
+//--------------------------------------------------------------
+*/
+
+static
+void unpack14 (const unsigned char b[14], unsigned short s[16])
+{
+    //
+    // Unpack a 14-byte block into 4 by 4 16-bit pixels.
+    //
+    unsigned short shift,bias;
+    #if defined (DEBUG)
+        assert (b[2] != 0xfc);
+    #endif
+    s[ 0] = (b[0] << 8) | b[1];
+    shift = (b[ 2] >> 2);
+    bias = (0x20 << shift);
+    s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) -
bias;
+    s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) -
bias;
+    s[12] = s[ 8] +   ((b[ 4]                       & 0x3f) << shift) -
bias;
+    s[ 1] = s[ 0] +   ((b[ 5] >> 2)                         << shift) -
bias;
+    s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) -
bias;
+    s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) -
bias;
+    s[13] = s[12] +   ((b[ 7]                       & 0x3f) << shift) -
bias;
+    s[ 2] = s[ 1] +   ((b[ 8] >> 2)                         << shift) -
bias;
+    s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) -
bias;
+    s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) -
bias;
+    s[14] = s[13] +   ((b[10]                       & 0x3f) << shift) -
bias;
+    s[ 3] = s[ 2] +   ((b[11] >> 2)                         << shift) -
bias;
+    s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) -
bias;
+    s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) -
bias;
+    s[15] = s[14] +   ((b[13]                       & 0x3f) << shift) -
bias;
+    for (int i = 0; i < 16; ++i) {
+        if (s[i] & 0x8000)
+            s[i] &= 0x7fff;
+        else
+            s[i] = ~s[i];
+    }
+}
+
+
+static void unpack3 (const unsigned char b[3], unsigned short s[16])
+{
+    //
+    // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
+    //
+    #if defined (DEBUG)
+        assert (b[2] == 0xfc);
+    #endif
+    s[0] = (b[0] << 8) | b[1];
+    if (s[0] & 0x8000)
+        s[0] &= 0x7fff;
+    else
+        s[0] = ~s[0];
+    for (int i = 1; i < 16; ++i)
+        s[i] = s[0];
+}
+
+
+
+static int b44_uncompress(EXRContext *s, const uint8_t *src,int
compressed_size, int uncompressed_size,
+EXRThreadData *td)
+{
+    unsigned long dest_len = uncompressed_size;
+    uint8_t *out;
+    int c, i, j;
+    uint16_t *ptr;
+    uint16_t *tmp = (uint16_t *)td->tmp;
+    unsigned short *tmpBufferEnd = tmp;
+    out = td->uncompressed_data;
+    if (uncompress(td->tmp, &dest_len, src, compressed_size) != Z_OK ||
+        dest_len != uncompressed_size)
+    return AVERROR_INVALIDDATA;
+    for (c = 0; c < s->nb_channels; c++,i++) {
+        EXRChannelData *cd = &s->channel_data[c];
+        cd->start = tmp;
+        cd->end = cd->start;
+        tmpBufferEnd += s->xdelta * s->ydelta * cd->size;
+    }
+    for (i = 0; i < s->nb_channels; i++) {
+        EXRChannel *channel = &s->channels[i];
+        int size = channel->pixel_type;
+        const char *inPtr=src;
+        int inSize = compressed_size;
+        ptr = tmp;
+        if (channel->pixel_type != EXR_HALF) {
+            //
+            // UINT or FLOAT channel.
+            //
+            int n = s->xdelta * s->ydelta * size * sizeof (unsigned short);
+            memcpy (ptr, inPtr, n);
+            inPtr += n;
+            inSize -= n;
+            continue;
+        } else {
+            //EXR_HALF Channel
+            for (int y=0; y < s->ydelta; y +=4 ) {
+                unsigned short *row0 = ptr + y * s->xdelta;
+                unsigned short *row1 = row0 + s->xdelta;
+                unsigned short *row2 = row1 + s->xdelta;
+                unsigned short *row3 = row2 + s->xdelta;
+
+                for (int x = 0; x < s->xdelta; x += 4) {
+                    unsigned short stmp[16];
+                    if (((const unsigned char *)inPtr)[2] == 0xfc) {
+                        unpack3 ((const unsigned char *)inPtr, stmp);
+                        inPtr += 3;
+                        inSize -= 3;
+                    } else {
+                        unpack14 ((const unsigned char *)inPtr, stmp);
+                        inPtr += 14;
+                        inSize -= 14;
+                    }
+                    int num = (x + 3 < s->xdelta)? 4 * sizeof (unsigned
short) : (s->xdelta - x) * sizeof (unsigned short);
+                    if (y + 3 < s->ydelta) {
+                        memcpy (row0, &stmp[ 0], num);
+                        memcpy (row1, &stmp[ 4], num);
+                        memcpy (row2, &stmp[ 8], num);
+                        memcpy (row3, &stmp[12], num);
+                    } else {
+                        memcpy (row0, &stmp[ 0], num);
+                        if (y + 1 < s->ydelta)
+                            memcpy (row1, &stmp[ 4], num);
+                        if (y + 2 < s->ydelta)
+                            memcpy (row2, &stmp[ 8], num);
+                    }
+                    row0 += 4;
+                    row1 += 4;
+                    row2 += 4;
+                    row3 += 4;
+                }
+            }
+        }
+    }
+    for (i = 0; i < s->ysize; i++) {
+        for (j = 0; j < s->nb_channels; j++) {
+            uint16_t *in = tmp + j * s->xdelta * s->ysize + i * s->xdelta;
+            memcpy(out, in, s->xdelta * 2);
+            out += s->xdelta * 2;
+        }
+    }
+    return 0;
+}
+
+
+
+
+
 static int pxr24_uncompress(EXRContext *s, const uint8_t *src,
                             int compressed_size, int uncompressed_size,
                             EXRThreadData *td)
@@ -888,6 +1160,8 @@ static int decode_block(AVCodecContext *avctx, void
*tdata,
             break;
         case EXR_RLE:
             ret = rle_uncompress(src, data_size, uncompressed_size, td);
+        case EXR_B44:
+            ret = b44_uncompress(s, src, data_size, uncompressed_size, td);
         }
         if (ret < 0) {
             av_log(avctx, AV_LOG_ERROR, "decode_block() failed.\n");
@@ -1282,6 +1556,7 @@ static int decode_frame(AVCodecContext *avctx, void
*data,
         s->scan_lines_per_block = 16;
         break;
     case EXR_PIZ:
+    case EXR_B44:
         s->scan_lines_per_block = 32;
         break;
     default:


/*

Patch included a new compression technique B44 which is a lossy compression
technique.
Its done as a part of qualification tast of GSoc 15 for organisation FFMPeg
copyrights @ Greeshma


*/



Best Regards
Greeshma
-------------- next part --------------
A non-text attachment was scrubbed...
Name: git diff2
Type: application/octet-stream
Size: 10087 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20150316/19349f0f/attachment.obj>


More information about the ffmpeg-devel mailing list