10 Replies Latest reply: Apr 20, 2012 9:33 AM by andrey.mironov RSS

    libjpeg / debug

    Piotr Wierzgała Community Member

      Hi,

       

      I need to use efficient jpeg encoder in my air project but all compiled libraried i've found* have memory leaks.

       

      * libraries i've found:

      1) http://www.websector.de/blog/2009/06/21/speed-up-jpeg-encoding-using-alchemy/

      2) http://segfaultlabs.com/devlogs/alchemy-asynchronous-jpeg-encoding

       

      I decided to compile code from page 2) and I succeeded but it produces completly black images. I couldn't find anything wrong in the code just by reading it so I started to wonder how could I debug it to find what causes the problem.

       

      For example there's a loop where argb row is converted to rgb:

       

      for ( j=0,i=0; i<row_stride; i+=3, j+=4 ) {

           rgbRow[i+2] = argbRow[j+3];

           rgbRow[i+1] = argbRow[j+2];

           rgbRow[i] = argbRow[j+1];

      };

       

      I assume that bitmapData passed to alchemy jpeg enocoder is correct and that libjpeg encoding functions work fine. I'd like to check if bytes in rgbRow are not zeros but I can't find a way how. Could anyone help me, please?

        • 1. Re: libjpeg / debug
          Bernd Paradies Adobe Employee

          Hello Piotr,

           

          Flash uses RGBA and LSB .

          http://en.wikipedia.org/wiki/Least_significant_bit

          Your code does not take the alpha channel into account.

           

          Please have a look at this post and search for onFrame()

          http://forums.adobe.com/thread/689742?tstart=0

           

          There are also other posts that explain how to deal with sharing ByteArrays between C and AS.

          This post might help too:

          http://forums.adobe.com/message/2976678#2976678

           

          Good luck,

           

          - Bernd

          • 2. Re: libjpeg / debug
            davr64 Community Member

            I use the library in #2, there's no memory leak (assuming you don't count the 2MB that's required for Alchemy, and only use 1 instance of the library instead of creating multiple). If I get a chance I'll compare my .c file with his to see if there's anything different that might be causing trouble for you.
            It's a very nice library, it's like 10x as fast as the AS3-only jpeg libraries. The JPEGs I'm encoding aren't too big (640x480 max), so I don't even use the async library call, since that is a bit slower

            • 3. Re: libjpeg / debug
              Piotr Wierzgała Community Member

              @Bernd

               

              I tried to use your byte array sharing method to rebuild my libjpeg wrapper but it doesn't work as expected. I was following instructions in your post and hopefully didn't make any mistake.

               

              Here's sample application I wrote to present the problem: application (source is enabled).

               

              When you click "fill button" green area below should change it's color to red.

               

              And here's the alchemy C code I used to build library enclosed in the project above: C source.

               

              Could you have a look at it and tell me what may I do wrong?  (The code is as simple as possible)

              • 4. Re: libjpeg / debug
                Piotr Wierzgała Community Member

                Oops, my bad

                 

                Alpha channel in your example was set to 0. Besides that it seems that flash is not using RGBA and LSB but ARGB and MSB what is confirmed by BitmapData docs.

                 

                When I changed C code from:

                 

                 

                imageBuffer[i + 0] = red;
                imageBuffer[i + 1] = green;
                imageBuffer[i + 2] = blue;
                imageBuffer[i + 3] = alpha;
                

                 

                 

                to:


                 

                imageBuffer[i + 0] = blue; 
                imageBuffer[i + 1] = green;
                imageBuffer[i + 2] = red;
                imageBuffer[i + 3] = alpha;
                

                 

                 

                it started to work.

                 

                @josath

                Could you share with me library you use to encode jpeg files?

                • 5. Re: libjpeg / debug
                  davr64 Community Member

                  Here's the C code I'm using:

                   

                   

                  /***

                       asynchronous jpeg encoding

                       see it in action at :
                            http://segfaultlabs.com/blog/post/asynchronous-jpeg-encoding

                       author: Mateusz Malczak ( http://segfaultlabs.com )

                  ***/
                  #include <AS3.h>
                  #include <stdio.h>
                  #include <setjmp.h>
                  #include "jerror.h"
                  #include "jpeglib.h"

                  /* read, write, seek, close a File inside Alchemy, File = ByteArray */
                  static int readba(void *cookie, char *dst, int size)
                  {
                       return AS3_ByteArray_readBytes(dst, (AS3_Val)cookie, size);
                  }

                  static int writeba(void *cookie, const char *src, int size)
                  {
                       return AS3_ByteArray_writeBytes((AS3_Val)cookie, (char *)src, size);
                  }

                  static fpos_t seekba(void *cookie, fpos_t offs, int whence)
                  {
                       return AS3_ByteArray_seek((AS3_Val)cookie, offs, whence);
                  }

                  static int closeba(void *cookie)
                  {
                       AS3_Val zero = AS3_Int(0);
                       AS3_SetS((AS3_Val)cookie, "position", zero);
                       AS3_Release(zero);
                       return 0;
                  }


                  AS3_Val fileTest( void *data, AS3_Val args )
                  {
                       /* image dimensions and compression quality */
                       int image_width = 0;
                       int image_height = 0;
                       int quality = 0;
                            
                       AS3_Val source;

                       AS3_Val dest;
                       
                       /* parse arguments passed from as3 code */
                       AS3_ArrayValue( args, "AS3ValType, AS3ValType, IntType, IntType, IntType", &source, &dest, &image_width, &image_height, &quality );

                       /* open bytearrayy stream */
                       FILE *output = funopen((void *)dest, readba, writeba, seekba, closeba);

                       /* jpeg code based on libjpeg example */
                       struct jpeg_compress_struct cinfo;
                       struct jpeg_error_mgr jerr;
                       unsigned char *argbRow = (unsigned char *)malloc( image_width * 4 );
                       JSAMPROW row_pointer[1];     
                       /* Step 1: allocate and initialize JPEG compression object */
                       cinfo.err = jpeg_std_error(&jerr);
                       jpeg_create_compress(&cinfo);
                       jpeg_stdio_dest(&cinfo, output);
                       /* Step 3: set parameters for compression */
                       cinfo.image_width = image_width;      /* image width and height, in pixels */
                       cinfo.image_height = image_height;
                       cinfo.input_components = 3;          /* # of color components per pixel */
                       cinfo.in_color_space = JCS_RGB;      /* colorspace of input image */
                       jpeg_set_defaults(&cinfo);
                       jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
                       /* Step 4: Start compressor */
                       jpeg_start_compress(&cinfo, TRUE);
                       /* Step 5: while (scan lines remain to be written) */
                       int i,j, yeld;
                       int argb_row_stride = image_width * 4;
                       int row_stride = image_width * 3;     /* JSAMPLEs per row in image_buffer */
                       yeld = 0;
                       while (cinfo.next_scanline < cinfo.image_height)
                       {
                            /* get lne from input */
                            AS3_ByteArray_readBytes( argbRow, source, argb_row_stride );          
                            /* skip alpha channel */
                                 for ( j=1,i=0; i<row_stride; i+=3,j+=4 )
                                      *(unsigned int*)(argbRow+i) = *(unsigned int*)(argbRow+j);
                            row_pointer[0] = & argbRow[0];
                            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
                            /* next 6 lines can be used to tune asynchronous performance
                             * the more flyield's calls, the faster function runs, but
                             * also more flash player slow downs
                             */
                                 yeld += 1;
                                      if ( yeld > 10 )
                                      {
                                           yeld = 0;
                                           flyield();
                                      };
                       }
                       
                       free( argbRow );
                       
                       /* Step 6: Finish compression */
                       jpeg_finish_compress(&cinfo);
                       /* Step 7: release JPEG compression object */
                       jpeg_destroy_compress(&cinfo);
                       
                       fclose( output );

                       AS3_Release( source ); // release hold on var passed in
                       
                       return dest; // returning var auto releases hold on it
                  };

                  int main()
                  {
                       AS3_Val encodeAsync_ = AS3_FunctionAsync( NULL, fileTest );
                       AS3_Val encode_ = AS3_Function( NULL, fileTest );
                       AS3_Val airobj = AS3_Object("encodeAsync: AS3ValType, encode: AS3ValType",
                                                          encodeAsync_,
                                                          encode_ );
                       AS3_Release( encodeAsync_ );
                       AS3_Release( encode_ );
                       AS3_LibInit( airobj );
                       return 0;
                  };
                  • 6. Re: libjpeg / debug
                    davr64 Community Member

                    And here's how I call it from actionscript:

                     

                        static private var alchemyJpeg:Object = null; // Alchemy JPEG library

                        static private function initAlchemy():void {
                            /* init alchemy object */
                            var init:CLibInit = new CLibInit(); //get library obejct
                            alchemyJpeg = init.init(); // initialize library exported class
                        }


                        static private function encodeJpeg(bd:BimapData):ByteArray {
                            var pixels:ByteArray = bd.getPixels(bd.rect);
                            var bytes:ByteArray = new ByteArray();
                            pixels.position = 0;
                            if(alchemyJpeg == null)
                                initAlchemy();
                            alchemyJpeg.encode( pixels, bytes, bd.width, bd.height, 80 );
                            return bytes;
                        }

                    • 7. Re: libjpeg / debug
                      Piotr Wierzgała Community Member

                      @josath

                      Your code works perfectly well.

                       

                      The only thing that differs my and yours code is the way you skip alpha channel and that you set source byte array position property to zero.

                       

                      I suppose that my output jpegs were completly black because I didn't set my source byte array pozition property to zero.

                       

                      Thank you you VERY much for supplying that code.

                      • 8. Re: libjpeg / debug
                        jasonzhuang

                        @Wierzgala

                        Thanks for posting the C source code, it's really useful.

                        • 9. Re: libjpeg / debug
                          jasonzhuang Community Member

                          @davr64

                          When the bytes retrieves from C, I use Image.source = bytes, can't display the image, could you help me?

                          • 10. Re: libjpeg / debug
                            andrey.mironov Community Member

                            @jasonzhuang,

                             

                            Try something like:

                                var loader:flash.display.Loader = new flash.display.Loader();
                                loader
                            .contentLoaderInfo.addEventListener(Event.COMPLETE, function (e:Event) : void {
                                    image.source
                            = new Bitmap(loader.content);
                               
                            });
                                loader
                            .loadBytes(bytes);