From dcf652223a7c9720f2524f466dabe186b80e3b44 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Fri, 9 Aug 2013 14:40:31 -0700 Subject: [PATCH] Support for 'do not blend' option in vwebp Change-Id: I563e192fa727816d11d8647c559ec407205ef40b --- examples/vwebp.c | 90 +++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/examples/vwebp.c b/examples/vwebp.c index f13b88fc..eeaddc86 100644 --- a/examples/vwebp.c +++ b/examples/vwebp.c @@ -60,12 +60,8 @@ static struct { WebPDecoderConfig* config; const WebPDecBuffer* pic; WebPDemuxer* dmux; - WebPIterator frameiter; - struct { - int width, height; - int x_offset, y_offset; - enum WebPMuxAnimDispose dispose_method; - } prev_frame; + WebPIterator curr_frame; + WebPIterator prev_frame; WebPChunkIterator iccp; } kParams; @@ -77,7 +73,8 @@ static void ClearPreviousPic(void) { static void ClearParams(void) { ClearPreviousPic(); WebPDataClear(&kParams.data); - WebPDemuxReleaseIterator(&kParams.frameiter); + WebPDemuxReleaseIterator(&kParams.curr_frame); + WebPDemuxReleaseIterator(&kParams.prev_frame); WebPDemuxReleaseChunkIterator(&kParams.iccp); WebPDemuxDelete(kParams.dmux); kParams.dmux = NULL; @@ -147,25 +144,25 @@ static int ApplyColorProfile(const WebPData* const profile, //------------------------------------------------------------------------------ // File decoding -static int Decode(void) { // Fills kParams.frameiter - const WebPIterator* const iter = &kParams.frameiter; +static int Decode(void) { // Fills kParams.curr_frame + const WebPIterator* const curr = &kParams.curr_frame; WebPDecoderConfig* const config = kParams.config; WebPDecBuffer* const output_buffer = &config->output; int ok = 0; ClearPreviousPic(); output_buffer->colorspace = MODE_RGBA; - ok = (WebPDecode(iter->fragment.bytes, iter->fragment.size, + ok = (WebPDecode(curr->fragment.bytes, curr->fragment.size, config) == VP8_STATUS_OK); if (!ok) { - fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num); + fprintf(stderr, "Decoding of frame #%d failed!\n", curr->frame_num); } else { kParams.pic = output_buffer; if (kParams.use_color_profile) { ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer); if (!ok) { fprintf(stderr, "Applying color profile to frame #%d failed!\n", - iter->frame_num); + curr->frame_num); } } } @@ -176,10 +173,10 @@ static void decode_callback(int what) { if (what == 0 && !kParams.done) { int duration = 0; if (kParams.dmux != NULL) { - WebPIterator* const iter = &kParams.frameiter; - if (!WebPDemuxNextFrame(iter)) { - WebPDemuxReleaseIterator(iter); - if (WebPDemuxGetFrame(kParams.dmux, 1, iter)) { + WebPIterator* const curr = &kParams.curr_frame; + if (!WebPDemuxNextFrame(curr)) { + WebPDemuxReleaseIterator(curr); + if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) { --kParams.loop_count; kParams.done = (kParams.loop_count == 0); } else { @@ -188,7 +185,7 @@ static void decode_callback(int what) { return; } } - duration = iter->duration; + duration = curr->duration; } if (!Decode()) { kParams.decoding_error = 1; @@ -281,40 +278,45 @@ static void DrawCheckerBoard(void) { static void HandleDisplay(void) { const WebPDecBuffer* const pic = kParams.pic; - const WebPIterator* const iter = &kParams.frameiter; + const WebPIterator* const curr = &kParams.curr_frame; + WebPIterator* const prev = &kParams.prev_frame; GLfloat xoff, yoff; if (pic == NULL) return; glPushMatrix(); glPixelZoom(1, -1); - xoff = (GLfloat)(2. * iter->x_offset / kParams.canvas_width); - yoff = (GLfloat)(2. * iter->y_offset / kParams.canvas_height); + xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width); + yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height); glRasterPos2f(-1.f + xoff, 1.f - yoff); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4); - if (kParams.prev_frame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { + if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND || + curr->blend_method == WEBP_MUX_NO_BLEND) { // TODO(later): these offsets and those above should factor in window size. // they will be incorrect if the window is resized. // glScissor() takes window coordinates (0,0 at bottom left). - const int window_x = kParams.prev_frame.x_offset; - const int window_y = kParams.canvas_height - - kParams.prev_frame.y_offset - - kParams.prev_frame.height; + int window_x, window_y; + if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { + // Clear the previous frame rectangle. + window_x = prev->x_offset; + window_y = kParams.canvas_height - prev->y_offset - prev->height; + } else { // curr->blend_method == WEBP_MUX_NO_BLEND. + // We simulate no-blending behavior by first clearing the current frame + // rectangle (to a checker-board) and then alpha-blending against it. + window_x = curr->x_offset; + window_y = kParams.canvas_height - curr->y_offset - curr->height; + } glEnable(GL_SCISSOR_TEST); - // Only updated the requested area, not the whole canvas. - glScissor(window_x, window_y, - kParams.prev_frame.width, kParams.prev_frame.height); + // Only update the requested area, not the whole canvas. + glScissor(window_x, window_y, prev->width, prev->height); glClear(GL_COLOR_BUFFER_BIT); // use clear color DrawCheckerBoard(); glDisable(GL_SCISSOR_TEST); } - kParams.prev_frame.width = iter->width; - kParams.prev_frame.height = iter->height; - kParams.prev_frame.x_offset = iter->x_offset; - kParams.prev_frame.y_offset = iter->y_offset; - kParams.prev_frame.dispose_method = iter->dispose_method; + + *prev = *curr; glDrawPixels(pic->width, pic->height, GL_RGBA, GL_UNSIGNED_BYTE, @@ -330,9 +332,9 @@ static void HandleDisplay(void) { glColor4f(0.90f, 0.0f, 0.90f, 1.0f); glRasterPos2f(-0.95f, 0.80f); PrintString(tmp); - if (iter->x_offset != 0 || iter->y_offset != 0) { + if (curr->x_offset != 0 || curr->y_offset != 0) { snprintf(tmp, sizeof(tmp), " (offset:%d,%d)", - iter->x_offset, iter->y_offset); + curr->x_offset, curr->y_offset); glRasterPos2f(-0.95f, 0.70f); PrintString(tmp); } @@ -386,6 +388,8 @@ static void Help(void) { int main(int argc, char *argv[]) { WebPDecoderConfig config; int c; + const WebPIterator* const curr = &kParams.curr_frame; + WebPIterator* const prev = &kParams.prev_frame; if (!WebPInitDecoderConfig(&config)) { fprintf(stderr, "Library version mismatch!\n"); @@ -457,10 +461,10 @@ int main(int argc, char *argv[]) { printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height); } - kParams.prev_frame.width = kParams.canvas_width; - kParams.prev_frame.height = kParams.canvas_height; - kParams.prev_frame.x_offset = kParams.prev_frame.y_offset = 0; - kParams.prev_frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; + prev->width = kParams.canvas_width; + prev->height = kParams.canvas_height; + prev->x_offset = prev->y_offset = 0; + prev->dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; memset(&kParams.iccp, 0, sizeof(kParams.iccp)); kParams.has_color_profile = @@ -476,20 +480,20 @@ int main(int argc, char *argv[]) { #endif } - if (!WebPDemuxGetFrame(kParams.dmux, 1, &kParams.frameiter)) goto Error; + if (!WebPDemuxGetFrame(kParams.dmux, 1, curr)) goto Error; - kParams.has_animation = (kParams.frameiter.num_frames > 1); + kParams.has_animation = (curr->num_frames > 1); kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT); kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR); printf("VP8X: Found %d images in file (loop count = %d)\n", - kParams.frameiter.num_frames, kParams.loop_count); + curr->num_frames, kParams.loop_count); // Decode first frame if (!Decode()) goto Error; // Position iterator to last frame. Next call to HandleDisplay will wrap over. // We take this into account by bumping up loop_count. - WebPDemuxGetFrame(kParams.dmux, 0, &kParams.frameiter); + WebPDemuxGetFrame(kParams.dmux, 0, curr); if (kParams.loop_count) ++kParams.loop_count; // Start display (and timer)