Advertisement
Guest User

Mondain

a guest
Oct 1st, 2010
298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 6.88 KB | None | 0 0
  1. package com.altair.codec;
  2.  
  3. import org.apache.mina.common.ByteBuffer;
  4.  
  5. import com.jcraft.jzlib.JZlib;
  6. import com.jcraft.jzlib.ZStream;
  7.  
  8. /**
  9.  * Flash Screen Video encoder <br /> Converted to Java from FFmpeg source
  10.  * authored by Alex Beregszaszi and Benjamin Larsson
  11.  * <br />
  12.  * Bitstream description The picture is divided into blocks that are zlib-compressed.
  13.  *
  14.  * The decoder is fed complete frames, the frameheader contains: 4bits of block
  15.  * width 12bits of frame width 4bits of block height 12bits of frame height
  16.  *
  17.  * Directly after the header are the compressed blocks. The blocks have their
  18.  * compressed size represented with 16bits in the begining. If the size = 0 then
  19.  * the block is unchanged from the previous frame. All blocks are decompressed
  20.  * until the buffer is consumed.
  21.  *
  22.  * Encoding ideas, a basic encoder would just use a fixed block size. Block
  23.  * sizes can be multiples of 16, from 16 to 256. The blocks don't have to be
  24.  * quadratic. A brute force search with a set of different block sizes should
  25.  * give a better result than to just use a fixed size.
  26.  *
  27.  * TODO: Don't reencode the frame in brute force mode if the frame is a dupe.
  28.  * Speed up. Make the difference check faster.
  29.  *
  30.  * @author Paul Gregoire (mondain@gmail.com)
  31.  */
  32. public class Encoder {
  33.  
  34.     // "Flash Screen Video"
  35.     // flashsv PIX_FMT_BGR24
  36.  
  37.     private int image_width;
  38.     private int image_height;
  39.     private int block_width = 64;
  40.     private int block_height = 64;
  41.  
  42.     private Frame previousFrame;
  43.  
  44.     private byte[] tmpblock;
  45.     private byte[] encbuffer;
  46.  
  47.     private int block_size;
  48.  
  49.     private ZStream zstream;
  50.  
  51.     private int frameNumber = 0;
  52.  
  53.     private int copy_region_enc(byte[] sptr, byte[] dptr, int dx, int dy, int h, int w, int stride) {
  54.  
  55.         int copyLength = w * 3;
  56.  
  57.         byte[] nsptr = new byte[copyLength];
  58.         byte[] npfptr = new byte[copyLength];
  59.         int diff = 0;
  60.            
  61.         byte[] tmp = previousFrame.getData().asReadOnlyBuffer().array();
  62.        
  63.         int destIndex = 0;
  64.        
  65.         for (int i = dx + h; i > dx; i--) {
  66.             int index = (i * stride) + dy * 3;
  67.             System.arraycopy(sptr, index, nsptr, 0, copyLength);
  68.             System.arraycopy(tmp, index, npfptr, 0, copyLength);
  69.             for (int j = 0; j < w * 3; j++) {
  70.                 diff |= npfptr[j] ^ nsptr[j];
  71.                 dptr[j + destIndex] = nsptr[j];
  72.             }
  73.             destIndex += copyLength;
  74.         }
  75.         if (diff != 0) {
  76.             return 1;
  77.         }
  78.         return 0;
  79.     }
  80.  
  81.     public int init(int width, int height) {
  82.  
  83.         if (width > 4095 || height > 4095) {
  84.             System.out
  85.                     .printf("Input dimensions too large, input must be max 4096x4096 !\n");
  86.             return -1;
  87.         }
  88.  
  89.         zstream = new ZStream();
  90.  
  91.         int err = zstream.deflateInit(JZlib.Z_BEST_COMPRESSION);
  92.         if (err == JZlib.Z_OK) {
  93.             System.out.printf("Deflate initialized");
  94.         } else {
  95.             System.out.printf("Deflate init failed error code: %s", err);
  96.             return -1;
  97.         }
  98.  
  99.         image_width = width;
  100.         image_height = height;
  101.  
  102.         tmpblock = new byte[3 * 256 * 256];
  103.         encbuffer = new byte[image_width * image_height * 3];
  104.  
  105.         return 0;
  106.     }
  107.  
  108.     public Frame encode(byte[] buf, int bufSize) {
  109.  
  110.         ByteBuffer outBuffer = ByteBuffer.allocate(bufSize * 8);
  111.         outBuffer.setAutoExpand(true);
  112.  
  113.         // 4 bits of block width
  114.         int width = (((block_width / 16) - 1) & 0x0f) << 4;
  115.         // 12 bits of frame width
  116.         width |= ((image_width & 0x0f00) >> 8) & 0x0f;
  117.  
  118.         outBuffer.putShort((short) width);
  119.  
  120.         // 4 bits of block height
  121.         int height = (((block_height / 16) - 1) & 0x0f) << 4;
  122.         // 12 bits of frame height
  123.         height |= ((image_height & 0x0f00) >> 8) & 0x0f;
  124.  
  125.         outBuffer.putShort((short) height);
  126.  
  127.         int predBlocks = 0;
  128.  
  129.         int h_blocks = image_width / block_width;
  130.         int h_part = image_width % block_width;
  131.         int v_blocks = image_height / block_height;
  132.         int v_part = image_height % block_height;
  133.  
  134.         // loop over all block columns
  135.         for (int j = 0; j < v_blocks + (v_part != 0 ? 1 : 0); j++) {
  136.  
  137.             int hp = j * block_height; // horiz position in frame
  138.             int hs = (j < v_blocks) ? block_height : v_part; // size of block
  139.  
  140.             // loop over all block rows
  141.             for (int i = 0; i < h_blocks + (h_part != 0 ? 1 : 0); i++) {
  142.                 int wp = i * block_width; // vert position in frame
  143.                 int ws = (i < h_blocks) ? block_width : h_part; // size of block
  144.                 int ret = JZlib.Z_OK;
  145.  
  146.                 // copy the block to the temp buffer before compression (if it
  147.                 // differs from the previous frame's block)
  148.                 int res = copy_region_enc(buf, tmpblock, image_height - (hp + hs + 1), wp, hs, ws, stride);
  149.  
  150.                 if (res != 0) {
  151.                     int zsize = 3 * block_width * block_height;
  152.  
  153.                     zstream.next_in = tmpblock;
  154.                     zstream.next_in_index = 0;
  155.  
  156.                     zstream.next_out = encbuffer;
  157.                     zstream.next_out_index = 0;
  158.  
  159.                     int sourceLength = 3 * ws * hs;
  160.                    
  161.                     while (zstream.total_in != sourceLength && zstream.total_out < zsize) {
  162.                         zstream.avail_in = zstream.avail_out = 1; // force small buffers
  163.                         ret = zstream.deflate(JZlib.Z_NO_FLUSH);
  164.                         if (ret != JZlib.Z_OK) {
  165.                             System.out.printf("Deflate loop1 failed error code: %d\n", ret);
  166.                         }
  167.                     }
  168.  
  169.                     while (true) {
  170.                         zstream.avail_out = 1;
  171.                         ret = zstream.deflate(JZlib.Z_FINISH);
  172.                         if (ret == JZlib.Z_STREAM_END) {
  173.                             break;
  174.                         }
  175.                         if (ret != JZlib.Z_OK) {
  176.                             System.out.printf("Deflate loop2 failed error code: %d\n", ret);
  177.                         }
  178.                     }
  179.  
  180.                     ret = zstream.deflateEnd();
  181.                     if (ret != JZlib.Z_OK) {
  182.                         System.out.printf(
  183.                                 "Error while compressing block %dx%d\n", i, j);
  184.                     }
  185.  
  186.                     outBuffer.putShort((short) zsize);
  187.                    
  188.                     //put the encoded / compressed bytes into the result
  189.                     outBuffer.put(encbuffer);
  190.  
  191.                     System.out.printf("buf_pos = %d\n", outBuffer.position());
  192.                 } else {
  193.                     predBlocks++;
  194.                     outBuffer.putShort((short) 0);
  195.                 }
  196.             }
  197.         }
  198.  
  199.         Frame outFrame = new Frame();
  200.         outFrame.setData(outBuffer);
  201.         outFrame.setFrameNumber(frameNumber);
  202.        
  203.         if (predBlocks != 0) {
  204.             outFrame.setFrameType(Frame.FRAME_TYPE_P);
  205.         } else {
  206.             outFrame.setFrameType(Frame.FRAME_TYPE_I);
  207.         }
  208.  
  209.         outFrame.setEncoded(true);
  210.        
  211.         return outFrame;
  212.     }
  213.  
  214.     public Frame encodeFrame(byte[] buf) {
  215.  
  216.         // First frame needs to be a keyframe
  217.         if (frameNumber == 0) {
  218.             previousFrame = new Frame();
  219.         }
  220.  
  221.         int bufSize = buf.length;
  222.         int bufferSizeEstimate = image_width * image_height * 3;
  223.  
  224.         if (bufSize < bufferSizeEstimate) {
  225.             // Conservative upper bound check for compressed data
  226.             System.out.printf("buf_size %d <  %d\n", bufSize, bufferSizeEstimate);
  227.             return null;
  228.         }
  229.  
  230.         Frame result = encode(buf, bufSize);
  231.  
  232.         // save the current frame
  233.         previousFrame.setData(result.getData());
  234.         previousFrame.setFrameNumber(frameNumber);
  235.         previousFrame.setFrameType(result.getFrameType());
  236.        
  237.         // mark the frame type so the muxer can mux it correctly
  238.         if (result.getFrameType() == Frame.FRAME_TYPE_I) {
  239.             System.out.printf("Inserting key frame at frame %d\n", frameNumber);
  240.         }
  241.        
  242.         frameNumber++;
  243.  
  244.         return result;
  245.     }
  246.  
  247. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement