gif: Add support for progressive animation encoding 83/60383/2
authorVineeth TM <vineeth.tm@samsung.com>
Wed, 24 Feb 2016 00:24:07 +0000 (09:24 +0900)
committerVineeth TM <vineeth.tm@samsung.com>
Fri, 26 Feb 2016 01:59:53 +0000 (10:59 +0900)
In case of systems with memory limitations, there should be a way to
continue with encoding as soon as we get each frame, instead of waiting for
all the frames.
But calling mm_util_encode_gif for each frame this can be achieved.

Change-Id: Ic134367143807f4f42bbe679ac36e83cf336bba6
Signed-off-by: Vineeth TM <vineeth.tm@samsung.com>
gif/include/mm_util_gif.h
gif/mm_util_gif.c
gif/test/mm_util_gif_testsuite.c

index f8df757..cc59046 100755 (executable)
@@ -37,6 +37,22 @@ extern "C" {
 */
 
 /**
+ * Read data attached to decoding callback
+ */
+typedef struct {
+       unsigned long long size;
+       void *mem;
+} read_data;
+
+/**
+ * Write data attached to encoding callback
+ */
+typedef struct {
+       unsigned long long size;
+       void **mem;
+} write_data;
+
+/**
  * format for gif
  */
 typedef enum
@@ -46,17 +62,21 @@ typedef enum
 
 typedef struct {
        unsigned long long delay_time;  /**< pre-display delay in 0.01sec units */
-       void *data;                     /**< data */
        unsigned long width;            /**< width */
        unsigned long height;           /**< height */
+       void *data;                     /**< data */
 } mm_util_gif_frame_data;
 
 typedef struct {
-       mm_util_gif_frame_data **frames;          /**< Frames*/
        unsigned long width;                      /**< width */
        unsigned long height;                     /**< height */
        unsigned long long size;                  /**< size */
        unsigned int image_count;                 /**< ImageCount */
+       bool screen_desc_updated;                 /**< Check if screen description is updated */
+       unsigned int current_count;               /**< ImageCount */
+       write_data write_data_ptr;                /**< Encoded output data attached to callback */
+       GifFileType *GifFile;                     /**< GifFile opened*/
+       mm_util_gif_frame_data **frames;          /**< Frames*/
 } mm_util_gif_data;
 
 /**
@@ -124,10 +144,9 @@ unsigned long long mm_util_gif_decode_get_size(mm_util_gif_data * data);
 #endif
 
 /**
- * This function encodes raw data to gif file
+ * This function creates gif file for output file
  *
  * @param encoded  [in ]    pointer of mm_util_gif_data.
- *                            After using it, please free the allocated memory.
  * @param filename [out]    output file name on to which the encoded stream will be written.
  * @return                  This function returns zero on success, or negative value with error code.
  * @remark                  image_count should be set to a valid value depending on number of images
@@ -135,13 +154,12 @@ unsigned long long mm_util_gif_decode_get_size(mm_util_gif_data * data);
  * @see                     mm_util_gif_data
  * @since                   R1, 1.0
  */
-int mm_util_encode_gif_to_file(mm_util_gif_data * encoded, const char *filename);
+int mm_util_encode_open_gif_file(mm_util_gif_data *encoded, const char *filename);
 
 /**
- * This function encodes raw data to gif memory
+ * This function creates gif file for output memory
  *
  * @param encoded  [in ]    pointer of mm_util_gif_data.
- *                          After using it, please free the allocated memory.
  * @param filename [out]    output file memory on to which the encoded stream will be written.
  * @return                  This function returns zero on success, or negative value with error code.
  * @remark                  image_count should be set to a valid value depending on number of images
@@ -149,7 +167,32 @@ int mm_util_encode_gif_to_file(mm_util_gif_data * encoded, const char *filename)
  * @see                     mm_util_gif_data
  * @since                   R1, 1.0
  */
-int mm_util_encode_gif_to_memory(mm_util_gif_data * encoded, void **memory);
+int mm_util_encode_open_gif_memory(mm_util_gif_data *encoded, void **data);
+
+/**
+ * This function encodes raw data to gif file/memory
+ *
+ * @param encoded  [in ]    pointer of mm_util_gif_data.
+ * @param filename [out]    output file name on to which the encoded stream will be written.
+ * @return                  This function returns zero on success, or negative value with error code.
+ * @remark                  image_count should be set to a valid value depending on number of images
+ *                          to be encoded in the gif file.
+ * @see                     mm_util_gif_data
+ * @since                   R1, 1.0
+ */
+int mm_util_encode_gif(mm_util_gif_data *encoded);
+
+/**
+ * This function closes and deallocates all the memory allocated with giffile.
+ *
+ * @param encoded  [in ]    pointer of mm_util_gif_data.
+ * @return                  This function returns zero on success, or negative value with error code.
+ * @remark                  image_count should be set to a valid value depending on number of images
+ *                          to be encoded in the gif file.
+ * @see                     mm_util_gif_data
+ * @since                   R1, 1.0
+ */
+int mm_util_encode_close_gif(mm_util_gif_data *encoded);
 
 /**
  * This function sets width of the encoded image.
index 0c1e739..3e35393 100755 (executable)
 #include "mm_util_gif.h"
 #include "mm_util_debug.h"
 
-typedef struct {
-       void *mem;
-       unsigned long long size;
-} read_data;
-typedef struct {
-       void **mem;
-       unsigned long long size;
-} write_data;
-
 static int __convert_gif_to_rgba(mm_util_gif_data *decoded, ColorMapObject *color_map, GifRowType *screen_buffer, unsigned long width, unsigned long height)
 {
        unsigned long i, j;
@@ -362,19 +353,6 @@ static int __save_buffer_to_gif(GifFileType *GifFile, GifByteType *OutputBuffer,
        return MM_UTIL_ERROR_NONE;
 }
 
-static void __outputbuffer_free(GifByteType **OutputBuffer, unsigned int image_count)
-{
-       unsigned int j;
-
-       for (j = 0; j < image_count; j++) {
-               if (OutputBuffer[j] != NULL)
-                       free((char *)OutputBuffer[j]);
-               else
-                       break;
-       }
-       free(OutputBuffer);
-}
-
 static int __write_function(GifFileType *gft, const GifByteType *data, int size)
 {
        write_data *write_data_ptr = (write_data *) gft->UserData;
@@ -387,51 +365,73 @@ static int __write_function(GifFileType *gft, const GifByteType *data, int size)
        return size;
 }
 
-#define ABS(x)    ((x) > 0 ? (x) : (-(x)))
-
-static int __write_gif(mm_util_gif_data *encoded, const char *filename, void **data)
+int mm_util_encode_open_gif_file(mm_util_gif_data *encoded, const char *filename)
 {
-       int ColorMapSize;
-       unsigned int i = 0;
-       GifByteType *red = NULL, *green = NULL, *blue = NULL, **OutputBuffer = NULL;
-       ColorMapObject *OutputColorMap = NULL;
-       GifFileType *GifFile;
-       write_data write_data_ptr;
-       unsigned char background_color;
-       int z;
-       int minIndex = 0, minDist = 0;
-       GifColorType *color;
-
+       mm_util_debug("mm_util_encode_open_gif_file");
        if (filename) {
-               if ((GifFile = EGifOpenFileName(filename, 0, NULL)) == NULL) {
+               if ((encoded->GifFile = EGifOpenFileName(filename, 0, NULL)) == NULL) {
                        mm_util_error("could not open file");
-                       __outputbuffer_free(OutputBuffer, encoded->image_count);
                        return MM_UTIL_ERROR_INVALID_OPERATION;
                }
-       } else {
-               write_data_ptr.mem = data;
-               write_data_ptr.size = 0;
+       } else
+               return MM_UTIL_ERROR_INVALID_PARAMETER;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_encode_open_gif_memory(mm_util_gif_data *encoded, void **data)
+{
+       mm_util_debug("mm_util_encode_open_gif_memory");
+       if (data) {
+               encoded->write_data_ptr.mem = data;
+               encoded->write_data_ptr.size = 0;
 
-               if ((GifFile = EGifOpen(&write_data_ptr, __write_function, NULL)) == NULL) {
+               if ((encoded->GifFile = EGifOpen(&(encoded->write_data_ptr), __write_function, NULL)) == NULL) {
                        mm_util_error("could not open File");
-                       __outputbuffer_free(OutputBuffer, encoded->image_count);
                        return MM_UTIL_ERROR_INVALID_OPERATION;
                }
-       }
+       } else
+               return MM_UTIL_ERROR_INVALID_PARAMETER;
 
-       if (EGifPutScreenDesc(GifFile, encoded->frames[0]->width, encoded->frames[0]->height, 8, 0, NULL) == GIF_ERROR) {
-               mm_util_error("could not put screen description");
-               if (GifFile != NULL)
-                       EGifCloseFile(GifFile, NULL);
-               __outputbuffer_free(OutputBuffer, encoded->image_count);
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_encode_close_gif(mm_util_gif_data *encoded)
+{
+       mm_util_debug("mm_util_encode_close_gif");
+       if (EGifCloseFile(encoded->GifFile, NULL) == GIF_ERROR) {
+               mm_util_error("could not close file");
                return MM_UTIL_ERROR_INVALID_OPERATION;
        }
 
-       for (i = 0; i < encoded->image_count; i++) {
-               OutputBuffer = (GifByteType **) realloc(OutputBuffer, (i + 1) * sizeof(GifByteType *));
-               if ((OutputBuffer[i] = (GifByteType *) malloc(encoded->frames[i]->width * encoded->frames[i]->height * sizeof(GifByteType))) == NULL) {
+       return MM_UTIL_ERROR_NONE;
+}
+
+#define ABS(x)    ((x) > 0 ? (x) : (-(x)))
+static int __write_gif(mm_util_gif_data *encoded)
+{
+       int ColorMapSize;
+       unsigned int i = encoded->current_count;
+       GifByteType *red = NULL, *green = NULL, *blue = NULL, *OutputBuffer = NULL;
+       ColorMapObject *OutputColorMap = NULL;
+       unsigned char background_color;
+       int z;
+       int minIndex = 0, minDist = 0;
+       GifColorType *color;
+
+       if (!encoded->screen_desc_updated) {
+               if (EGifPutScreenDesc(encoded->GifFile, encoded->frames[0]->width, encoded->frames[0]->height, 8, 0, NULL) == GIF_ERROR) {
+                       mm_util_error("could not put screen description");
+                       if (encoded->GifFile != NULL)
+                               EGifCloseFile(encoded->GifFile, NULL);
+                       return MM_UTIL_ERROR_INVALID_OPERATION;
+               }
+               encoded->screen_desc_updated = true;
+       }
+
+       for (i = encoded->current_count; i < encoded->image_count; i++) {
+               if ((OutputBuffer = (GifByteType *) malloc(encoded->frames[i]->width * encoded->frames[i]->height * sizeof(GifByteType))) == NULL) {
                        mm_util_error("Failed to allocate memory required, aborted.");
-                       __outputbuffer_free(OutputBuffer, encoded->image_count);
                        return MM_UTIL_ERROR_INVALID_OPERATION;
                }
 
@@ -440,18 +440,18 @@ static int __write_gif(mm_util_gif_data *encoded, const char *filename, void **d
 
                if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL) {
                        mm_util_error("could not map object");
-                       __outputbuffer_free(OutputBuffer, encoded->image_count);
                        free((char *)red);
                        free((char *)green);
                        free((char *)blue);
+                       free(OutputBuffer);
                        return MM_UTIL_ERROR_INVALID_OPERATION;
                }
-               if (GifQuantizeBuffer(encoded->frames[i]->width, encoded->frames[i]->height, &ColorMapSize, red, green, blue, OutputBuffer[i], OutputColorMap->Colors) == GIF_ERROR) {
+               if (GifQuantizeBuffer(encoded->frames[i]->width, encoded->frames[i]->height, &ColorMapSize, red, green, blue, OutputBuffer, OutputColorMap->Colors) == GIF_ERROR) {
                        mm_util_error("could not quantize buffer");
-                       __outputbuffer_free(OutputBuffer, encoded->image_count);
                        free((char *)red);
                        free((char *)green);
                        free((char *)blue);
+                       free(OutputBuffer);
                        return MM_UTIL_ERROR_INVALID_OPERATION;
                }
                free((char *)red);
@@ -477,41 +477,23 @@ static int __write_gif(mm_util_gif_data *encoded, const char *filename, void **d
                }
                background_color = minIndex;
 
-               if (__save_buffer_to_gif(GifFile, OutputBuffer[i], encoded->frames[0]->width, encoded->frames[0]->height, encoded->frames[i]->width, encoded->frames[i]->height, encoded->frames[i]->delay_time, OutputColorMap, background_color) != MM_UTIL_ERROR_NONE) {
-                       __outputbuffer_free(OutputBuffer, encoded->image_count);
+               if (__save_buffer_to_gif(encoded->GifFile, OutputBuffer, encoded->frames[0]->width, encoded->frames[0]->height, encoded->frames[i]->width, encoded->frames[i]->height, encoded->frames[i]->delay_time, OutputColorMap, background_color) != MM_UTIL_ERROR_NONE)
                        return MM_UTIL_ERROR_INVALID_OPERATION;
-               }
-       }
 
-       if (EGifCloseFile(GifFile, NULL) == GIF_ERROR) {
-               mm_util_error("could not close file");
-               __outputbuffer_free(OutputBuffer, encoded->image_count);
-               return MM_UTIL_ERROR_INVALID_OPERATION;
+               free(OutputBuffer);
+               encoded->current_count++;
        }
-
-       encoded->size = write_data_ptr.size;
-       __outputbuffer_free(OutputBuffer, encoded->image_count);
+       encoded->size = encoded->write_data_ptr.size;
 
        return MM_UTIL_ERROR_NONE;
 }
 
-int mm_util_encode_gif_to_file(mm_util_gif_data *encoded, const char *fpath)
-{
-       int ret;
-
-       mm_util_debug("mm_util_encode_to_gif");
-
-       ret = __write_gif(encoded, fpath, NULL);
-
-       return ret;
-}
-
-int mm_util_encode_gif_to_memory(mm_util_gif_data *encoded, void **data)
+int mm_util_encode_gif(mm_util_gif_data *encoded)
 {
        int ret;
 
-       mm_util_debug("mm_util_encode_to_memory");
-       ret = __write_gif(encoded, NULL, data);
+       mm_util_debug("mm_util_encode_gif");
+       ret = __write_gif(encoded);
 
        return ret;
 }
index 46f1b5a..b99ae12 100755 (executable)
@@ -69,7 +69,9 @@ int main(int argc, char *argv[])
                                        snprintf(filename, BUFFER_SIZE, "%s%s", DECODE_RESULT_PATH, "gif");
                                }
                                mm_util_gif_encode_set_image_count(&decoded, 1);
-                               ret = mm_util_encode_gif_to_file(&decoded, filename);
+                               ret = mm_util_encode_open_gif_file(&decoded, filename);
+                               ret = mm_util_encode_gif(&decoded);
+                               ret = mm_util_encode_close_gif(&decoded);
 
                                free(decoded.frames[0]->data);
                                free(decoded.frames);