[byzanz] Update Gifenc API
- From: Benjamin Otte <otte src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [byzanz] Update Gifenc API
- Date: Wed, 26 Aug 2009 10:21:27 +0000 (UTC)
commit ca30f58aace35e1b3f49d80cc4a068e1d4b99cd0
Author: Benjamin Otte <otte gnome org>
Date: Wed Aug 19 12:33:45 2009 +0200
Update Gifenc API
It now takes a write function and emits errors when writing to it fails.
This simplifies the gifenc API while making it more powerful at the same
time.
gifenc/gifenc.c | 147 +++++++++++++++++++++++++++-----------------------
gifenc/gifenc.h | 109 +++++++++++++++++++++----------------
src/byzanzrecorder.c | 48 ++++++++++++++---
3 files changed, 183 insertions(+), 121 deletions(-)
---
diff --git a/gifenc/gifenc.c b/gifenc/gifenc.c
index d633da0..c6fa246 100644
--- a/gifenc/gifenc.c
+++ b/gifenc/gifenc.c
@@ -52,20 +52,19 @@ log2n (guint number)
/*** WRITE ROUTINES ***/
-static void
-gifenc_write (Gifenc *enc, const guint8 *data, guint len)
+static gboolean
+gifenc_flush (Gifenc *enc, GError **error)
{
- ssize_t ret;
+ gboolean result;
- g_return_if_fail (enc->n_bits == 0);
-
- while (len > 0) {
- ret = write (enc->fd, data, len);
- if (ret < 0)
- g_assert_not_reached ();
- len -= ret;
- data += ret;
- }
+ if (enc->buffer->len == 0)
+ return TRUE;
+
+ result = enc->write_func (enc->write_data, enc->buffer->data,
+ enc->buffer->len, error);
+
+ g_byte_array_set_size (enc->buffer, 0);
+ return result;
}
static void
@@ -74,7 +73,7 @@ gifenc_write_uint16 (Gifenc *enc, guint16 value)
g_return_if_fail (enc->n_bits == 0);
value = GUINT16_TO_LE (value);
- gifenc_write (enc, (guint8 *) &value, 2);
+ g_byte_array_append (enc->buffer, (guint8 *) &value, 2);
}
static void
@@ -82,7 +81,7 @@ gifenc_write_byte (Gifenc *enc, guint8 value)
{
g_return_if_fail (enc->n_bits == 0);
- gifenc_write (enc, &value, 1);
+ g_byte_array_append (enc->buffer, &value, 1);
}
static void
@@ -108,21 +107,21 @@ gifenc_write_bits (Gifenc *enc, guint bits, guint nbits)
static void
gifenc_write_header (Gifenc *enc)
{
- gifenc_write (enc, (const guchar *) "GIF89a", 6);
+ g_byte_array_append (enc->buffer, (const guchar *) "GIF89a", 6);
}
static void
-gifenc_write_lsd (Gifenc *enc)
+gifenc_write_lsd (Gifenc *enc, GifencPalette *palette)
{
- g_assert (gifenc_palette_get_num_colors (enc->palette) >= 2);
+ g_assert (palette == NULL || gifenc_palette_get_num_colors (palette) >= 2);
gifenc_write_uint16 (enc, enc->width);
gifenc_write_uint16 (enc, enc->height);
- gifenc_write_bits (enc, enc->palette ? 1 : 0, 1); /* global color table flag */
+ gifenc_write_bits (enc, palette ? 1 : 0, 1); /* global color table flag */
gifenc_write_bits (enc, 0x7, 3); /* color resolution */
gifenc_write_bits (enc, 0, 1); /* sort flag */
- gifenc_write_bits (enc, enc->palette ?
- log2n (gifenc_palette_get_num_colors (enc->palette) - 1) - 1 : 0, 3); /* number of colors */
+ gifenc_write_bits (enc, palette ?
+ log2n (gifenc_palette_get_num_colors (palette) - 1) - 1 : 0, 3); /* number of colors */
gifenc_write_byte (enc, 0); /* background color */
gifenc_write_byte (enc, 0); /* pixel aspect ratio */
}
@@ -142,11 +141,11 @@ gifenc_write_color_table (Gifenc *enc, GifencPalette *palette)
gifenc_write_byte (enc, BLUE (palette->colors[i]));
}
if (palette->alpha) {
- gifenc_write (enc, (guint8 *) "\272\219\001", 3);
+ g_byte_array_append (enc->buffer, (guint8 *) "\272\219\001", 3);
i++;
}
for (; i < table_size; i++) {
- gifenc_write (enc, (guint8 *) "\0\0\0", 3);
+ g_byte_array_append (enc->buffer, (guint8 *) "\0\0\0", 3);
}
}
@@ -190,7 +189,7 @@ gifenc_buffer_write (Gifenc *enc, EncodeBuffer *buffer)
if (buffer->bytes == 0)
return;
gifenc_write_byte (enc, buffer->bytes);
- gifenc_write (enc, buffer->data, buffer->bytes);
+ g_byte_array_append (enc->buffer, buffer->data, buffer->bytes);
buffer->bytes = 0;
}
@@ -346,7 +345,7 @@ gifenc_write_loop (Gifenc *enc)
gifenc_write_byte (enc, 0x21); /* extension */
gifenc_write_byte (enc, 0xFF); /* application extension */
gifenc_write_byte (enc, 11); /* block size */
- gifenc_write (enc, (guint8 *) "NETSCAPE2.0", 11);
+ g_byte_array_append (enc->buffer, (guint8 *) "NETSCAPE2.0", 11);
gifenc_write_byte (enc, 3); /* block size */
gifenc_write_byte (enc, 1); /* ??? */
gifenc_write_byte (enc, 0); /* ??? */
@@ -357,86 +356,98 @@ gifenc_write_loop (Gifenc *enc)
/*** PUBLIC API ***/
Gifenc *
-gifenc_open (const char *filename, guint width, guint height)
-{
- int fd;
-
- g_return_val_if_fail (width <= G_MAXUINT16, NULL);
- g_return_val_if_fail (height <= G_MAXUINT16, NULL);
-
- fd = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0)
- return NULL;
-
- return gifenc_open_fd (fd, width, height);
-}
-
-Gifenc *
-gifenc_open_fd (gint fd, guint width, guint height)
+gifenc_new (guint width, guint height, GifencWriteFunc write_func,
+ gpointer write_data, GDestroyNotify write_destroy)
{
Gifenc *enc;
g_return_val_if_fail (width <= G_MAXUINT16, NULL);
g_return_val_if_fail (height <= G_MAXUINT16, NULL);
-
- enc = g_new0 (Gifenc, 1);
- enc->fd = fd;
+ g_return_val_if_fail (write_func, NULL);
+
+ enc = g_slice_new0 (Gifenc);
enc->width = width;
enc->height = height;
- //g_print ("created new image with size %ux%u\n", width, height);
- gifenc_write_header (enc);
-
+ enc->buffer = g_byte_array_new ();
+ enc->write_func = write_func;
+ enc->write_data = write_data;
+ enc->write_destroy = write_destroy;
+
return enc;
}
-void
-gifenc_set_palette (Gifenc *enc, GifencPalette *palette)
+gboolean
+gifenc_initialize (Gifenc *enc, GifencPalette *palette, gboolean loop, GError **error)
{
- g_return_if_fail (enc->palette == NULL);
- g_return_if_fail (palette != NULL);
+ g_return_val_if_fail (enc != NULL, FALSE);
+ g_return_val_if_fail (enc->state == GIFENC_STATE_NEW, FALSE);
+ g_return_val_if_fail (palette != NULL, FALSE);
+
+ gifenc_write_header (enc);
+ gifenc_write_lsd (enc, palette);
+ gifenc_write_color_table (enc, palette);
+ if (loop)
+ gifenc_write_loop (enc);
+ if (!gifenc_flush (enc, error))
+ return FALSE;
enc->palette = palette;
- gifenc_write_lsd (enc);
- gifenc_write_color_table (enc, enc->palette);
+ enc->state = GIFENC_STATE_INITIALIZED;
+ return TRUE;
}
-void
+gboolean
gifenc_add_image (Gifenc *enc, guint x, guint y, guint width, guint height,
- guint display_millis, guint8 *data, guint rowstride)
+ guint display_millis, guint8 *data, guint rowstride, GError **error)
{
GifencImage image = { x, y, width, height, NULL, data, rowstride };
- g_return_if_fail (x + width <= enc->width);
- g_return_if_fail (width > 0);
- g_return_if_fail (y + height <= enc->height);
- g_return_if_fail (height > 0);
+ g_return_val_if_fail (enc != NULL, FALSE);
+ g_return_val_if_fail (enc->state == GIFENC_STATE_INITIALIZED, FALSE);
+ g_return_val_if_fail (width > 0, FALSE);
+ g_return_val_if_fail (x + width <= enc->width, FALSE);
+ g_return_val_if_fail (height > 0, FALSE);
+ g_return_val_if_fail (y + height <= enc->height, FALSE);
//g_print ("adding image (display time %u)\n", display_millis);
gifenc_write_graphic_control (enc, image.palette ? image.palette : enc->palette,
display_millis);
gifenc_write_image_description (enc, &image);
gifenc_write_image_data (enc, &image);
+ return gifenc_flush (enc, error);
}
gboolean
-gifenc_close (Gifenc *enc)
+gifenc_close (Gifenc *enc, GError **error)
{
- gifenc_write_byte (enc, 0x3B);
- close (enc->fd);
+ g_return_val_if_fail (enc != NULL, FALSE);
+ g_return_val_if_fail (enc->state == GIFENC_STATE_INITIALIZED, FALSE);
- if (enc->palette)
- gifenc_palette_free (enc->palette);
- g_free (enc);
+ gifenc_write_byte (enc, 0x3B);
+ if (!gifenc_flush (enc, error))
+ return FALSE;
+ enc->state = GIFENC_STATE_CLOSED;
return TRUE;
}
-void
-gifenc_set_looping (Gifenc *enc)
+gboolean
+gifenc_free (Gifenc *enc)
{
- g_return_if_fail (enc != NULL);
+ gboolean success;
+
+ g_return_val_if_fail (enc != NULL, FALSE);
+
+ success = enc->state == GIFENC_STATE_CLOSED;
+
+ if (enc->write_destroy)
+ enc->write_destroy (enc->write_data);
+ if (enc->palette)
+ gifenc_palette_free (enc->palette);
+ g_byte_array_unref (enc->buffer);
+ g_slice_free (Gifenc, enc);
- gifenc_write_loop (enc);
+ return success;
}
/* Floyd-Steinman factors */
diff --git a/gifenc/gifenc.h b/gifenc/gifenc.h
index 4d43352..0b5c602 100644
--- a/gifenc/gifenc.h
+++ b/gifenc/gifenc.h
@@ -27,6 +27,14 @@ typedef struct _GifencPalette GifencPalette;
typedef struct _GifencColor GifencColor;
typedef struct _Gifenc Gifenc;
+typedef gboolean (* GifencWriteFunc) (gpointer closure, const guchar *data, gsize len, GError **error);
+
+typedef enum {
+ GIFENC_STATE_NEW = 0,
+ GIFENC_STATE_INITIALIZED,
+ GIFENC_STATE_CLOSED,
+} GifencState;
+
struct _GifencPalette {
gboolean alpha;
guint32 * colors;
@@ -40,8 +48,14 @@ struct _GifencPalette {
};
struct _Gifenc {
+ /* error checking */
+ GifencState state;
+
/* output */
- int fd;
+ GifencWriteFunc write_func;
+ gpointer write_data;
+ GDestroyNotify write_destroy;
+ GByteArray * buffer;
guint bits;
guint n_bits;
@@ -52,60 +66,63 @@ struct _Gifenc {
GifencPalette * palette;
};
-Gifenc * gifenc_open (const char * filename,
- guint width,
- guint height);
-Gifenc * gifenc_open_fd (int fd,
- guint width,
- guint height);
+Gifenc * gifenc_new (guint width,
+ guint height,
+ GifencWriteFunc write_func,
+ gpointer write_data,
+ GDestroyNotify write_destroy);
+gboolean gifenc_free (Gifenc * enc);
-void gifenc_set_palette (Gifenc * enc,
- GifencPalette *palette);
-void gifenc_set_looping (Gifenc * enc);
-void gifenc_add_image (Gifenc * enc,
- guint x,
- guint y,
- guint width,
- guint height,
- guint display_millis,
- guint8 * data,
- guint rowstride);
-gboolean gifenc_close (Gifenc * enc);
+gboolean gifenc_initialize (Gifenc * enc,
+ GifencPalette * palette,
+ gboolean loop,
+ GError ** error);
+gboolean gifenc_add_image (Gifenc * enc,
+ guint x,
+ guint y,
+ guint width,
+ guint height,
+ guint display_millis,
+ guint8 * data,
+ guint rowstride,
+ GError ** error);
+gboolean gifenc_close (Gifenc * gifenc,
+ GError ** error);
-void gifenc_dither_rgb (guint8 * target,
- guint target_rowstride,
+void gifenc_dither_rgb (guint8 * target,
+ guint target_rowstride,
const GifencPalette * palette,
- const guint8 * data,
- guint width,
- guint height,
- guint rowstride);
+ const guint8 * data,
+ guint width,
+ guint height,
+ guint rowstride);
gboolean gifenc_dither_rgb_with_full_image
- (guint8 * target,
- guint target_rowstride,
- guint8 * full,
- guint full_rowstride,
+ (guint8 * target,
+ guint target_rowstride,
+ guint8 * full,
+ guint full_rowstride,
const GifencPalette * palette,
- const guint8 * data,
- guint width,
- guint height,
- guint rowstride,
- GdkRectangle * rect_out);
+ const guint8 * data,
+ guint width,
+ guint height,
+ guint rowstride,
+ GdkRectangle * rect_out);
/* from quantize.c */
-void gifenc_palette_free (GifencPalette *palette);
-GifencPalette * gifenc_palette_get_simple (gboolean alpha);
-GifencPalette * gifenc_quantize_image (const guint8 * data,
- guint width,
- guint height,
- guint rowstride,
- gboolean alpha,
- guint max_colors);
+void gifenc_palette_free (GifencPalette * palette);
+GifencPalette * gifenc_palette_get_simple (gboolean alpha);
+GifencPalette * gifenc_quantize_image (const guint8 * data,
+ guint width,
+ guint height,
+ guint rowstride,
+ gboolean alpha,
+ guint max_colors);
guint gifenc_palette_get_alpha_index
- (const GifencPalette *palette);
+ (const GifencPalette * palette);
guint gifenc_palette_get_num_colors
- (const GifencPalette *palette);
-guint32 gifenc_palette_get_color(const GifencPalette *palette,
- guint id);
+ (const GifencPalette * palette);
+guint32 gifenc_palette_get_color(const GifencPalette * palette,
+ guint id);
#endif /* __HAVE_GIFENC_H__ */
diff --git a/src/byzanzrecorder.c b/src/byzanzrecorder.c
index e5dfc4d..df70e47 100644
--- a/src/byzanzrecorder.c
+++ b/src/byzanzrecorder.c
@@ -22,11 +22,13 @@
#endif
#include "byzanzrecorder.h"
+
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
+#include <errno.h>
#include <cairo.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
@@ -307,7 +309,7 @@ byzanz_recorder_add_image (ByzanzRecorder *rec, const GTimeVal *tv)
gifenc_add_image (rec->gifenc, rec->relevant_data.x, rec->relevant_data.y,
rec->relevant_data.width, rec->relevant_data.height, msecs,
rec->data + rec->area.width * rec->relevant_data.y + rec->relevant_data.x,
- rec->area.width);
+ rec->area.width, NULL);
rec->current = *tv;
}
}
@@ -461,9 +463,7 @@ byzanz_recorder_quantize (ByzanzRecorder *rec, cairo_surface_t *image)
palette = gifenc_quantize_image (cairo_image_surface_get_data (image),
rec->area.width, rec->area.height, cairo_image_surface_get_stride (image), TRUE, 255);
- gifenc_set_palette (rec->gifenc, palette);
- if (rec->loop)
- gifenc_set_looping (rec->gifenc);
+ gifenc_initialize (rec->gifenc, palette, rec->loop, NULL);
}
static gboolean
@@ -562,6 +562,7 @@ loop:
}
byzanz_recorder_add_image (rec, &quit_tv);
+ gifenc_close (rec->gifenc, NULL);
g_free (rec->data);
rec->data = NULL;
@@ -794,6 +795,38 @@ byzanz_recorder_new (const gchar *filename, GdkWindow *window, GdkRectangle *are
return byzanz_recorder_new_fd (fd, window, area, loop, record_cursor);
}
+static gboolean
+recorder_gifenc_write (gpointer closure, const guchar *data, gsize len, GError **error)
+{
+ gssize written;
+ int fd = GPOINTER_TO_INT (closure);
+
+ do {
+ written = write (fd, data, len);
+ if (written < 0) {
+ int err = errno;
+
+ if (err == EINTR)
+ continue;
+
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (err),
+ _("Error writing: %s"), g_strerror (err));
+ return FALSE;
+ } else {
+ len -= written;
+ data += written;
+ }
+ } while (len > 0);
+
+ return TRUE;
+}
+
+static void
+recorder_gifenc_close (gpointer closure)
+{
+ close (GPOINTER_TO_INT (closure));
+}
+
ByzanzRecorder *
byzanz_recorder_new_fd (gint fd, GdkWindow *window, GdkRectangle *area,
gboolean loop, gboolean record_cursor)
@@ -835,7 +868,8 @@ byzanz_recorder_new_fd (gint fd, GdkWindow *window, GdkRectangle *area,
gdk_drawable_get_size (recorder->window,
&root_rect.width, &root_rect.height);
gdk_rectangle_intersect (&recorder->area, &root_rect, &recorder->area);
- recorder->gifenc = gifenc_open_fd (fd, recorder->area.width, recorder->area.height);
+ recorder->gifenc = gifenc_new (recorder->area.width, recorder->area.height,
+ recorder_gifenc_write, GINT_TO_POINTER (fd), recorder_gifenc_close);
if (!recorder->gifenc) {
g_free (recorder);
return NULL;
@@ -846,7 +880,7 @@ byzanz_recorder_new_fd (gint fd, GdkWindow *window, GdkRectangle *area,
recorder->encoder = g_thread_create (byzanz_recorder_run_encoder, recorder,
TRUE, NULL);
if (!recorder->encoder) {
- gifenc_close (recorder->gifenc);
+ gifenc_free (recorder->gifenc);
g_async_queue_unref (recorder->jobs);
g_free (recorder);
return NULL;
@@ -965,7 +999,7 @@ byzanz_recorder_destroy (ByzanzRecorder *rec)
if (IS_RECORDING_CURSOR (rec))
g_hash_table_destroy (rec->cursors);
- gifenc_close (rec->gifenc);
+ gifenc_free (rec->gifenc);
g_object_unref (rec->window);
g_assert (g_async_queue_length (rec->jobs) == 0);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]